dali ver 1.2.27 devel-master branch code sync
[platform/core/csapi/tizenfx.git] / NUISamples / NUISamples.TizenTV / firstscreen / ScrollContainer.cs
1 using Tizen.NUI;
2 using Tizen.NUI.Constants;
3 using System;
4 using System.Runtime.InteropServices;
5 using System.Collections.Generic;
6
7 namespace FirstScreen
8 {
9     public class ScrollContainer : CustomView
10     {
11         private View _container;                      // View Container will be the first item added to ScrollContainer and parent to all the items added to the ScrollContainer.
12         private Size _itemSize;                    // Size of the item / images added to the ScrollContainer.
13         private List<View> _itemList;                 // List collection of View items/images  added to the ScrollContainer.
14         private int _itemCount;                       // Number of items / images  added to the ScrollContainer.
15         private int _focusedItem;                     // Index of currently focused View item / image  on the ScrollContainer.
16         private float _scrollDisplacement;            // Used for horizontal pan displacement.
17         private float _currentScrollPosition;         // Used for horizontal scroll position.
18         private float _gap;                           // Used for gap / padding between items / images on the ScrollContainer.
19         private float _width;                         // Width of the ScrollContainer.
20         private float _height;                        // Height of the ScrollContainer.
21         private bool _isFocused;                      // Flag to check if ScrollContainer is enabled or not.
22         private float _marginX;                       // Extra horizontal margin is used to add an extra gap between items / images after a focused and scaled item / image.
23         private float _marginY;                       // Extra vertical margin (not used at the moment).
24         private float _offsetYFactor;                 // Vertical Position offset Factor of item height.
25         private float _offsetX;                       // Horizontal Position offset of ScrollContainer.
26         private Stage _stage;                         // Reference to Dali stage.
27         private Size2D _stageSize;                    // Reference to Dali stage size.
28         private ImageView _shadowBorder;              // Reference to Shadow border ImageView applied to the focused item on ScrollContainer.
29         private ImageView _spotLight;                 // Reference to SpotLight ImageView applied to the focused item on ScrollContainer.
30         private Animation _spotLightAnimation;        // SpotLight Animation applied to the focused item on ScrollContainer.
31         private Animation _focusAnimation;            // Focused position animation on ScrollContainer.
32         private Animation _scrollAnimation;           // Scroll animation on items of ScrollContainer.
33         private Animation _focusTransitionAnimation;  // Focus Transition (scaling /unscaling) animation on items of ScrollContainer.
34         private Path _circularPath;                   // Circular path used for SpotLight Animation applied to the focused item on ScrollContainer.
35
36         public ScrollContainer() : base(ViewBehaviour.DisableStyleChangeSignals |
37                                         ViewBehaviour.RequiresKeyboardNavigationSupport)
38         {
39         }
40         public bool IsFocused
41         {
42             get
43             {
44                 return _isFocused;
45             }
46         }
47
48         public Tizen.NUI.View Container
49         {
50             get
51             {
52                 return _container;
53             }
54         }
55
56         public int ItemCount
57         {
58             get
59             {
60                 return _itemCount;
61             }
62         }
63
64         public Size ItemSize
65         {
66             get
67             {
68                 return _itemSize;
69             }
70
71             set
72             {
73                 _itemSize = value;
74
75                 Position topLeft = new Position(-0.25f * _itemSize.Width, -0.25f * _itemSize.Height, 0.0f);
76                 Position topRight = new Position(0.25f * _itemSize.Width, -0.25f * _itemSize.Height, 0.0f);
77                 Position bottomRight = new Position(0.25f * _itemSize.Width, 0.25f * _itemSize.Height, 0.0f);
78                 Position bottomLeft = new Position(-0.25f * _itemSize.Width, 0.25f * _itemSize.Height, 0.0f);
79
80                 _circularPath = new Path();
81                 _circularPath.AddPoint(topLeft);
82                 _circularPath.AddPoint(topRight);
83                 _circularPath.AddPoint(bottomRight);
84                 _circularPath.AddPoint(bottomLeft);
85                 _circularPath.AddPoint(topLeft);
86                 _circularPath.GenerateControlPoints(0.5f);
87             }
88         }
89
90         public float Gap
91         {
92             get
93             {
94                 return _gap;
95             }
96
97             set
98             {
99                 _gap = value;
100             }
101         }
102
103         public float MarginX
104         {
105             get
106             {
107                 return _marginX;
108             }
109
110             set
111             {
112                 _marginX = value;
113             }
114         }
115
116         public float OffsetYFator
117         {
118             get
119             {
120                 return _offsetYFactor;
121             }
122
123             set
124             {
125                 _offsetYFactor = value;
126             }
127         }
128
129         public float OffsetX
130         {
131             get
132             {
133                 return _offsetX;
134             }
135
136             set
137             {
138                 _offsetX = value;
139             }
140         }
141
142         public float MarginY
143         {
144             get
145             {
146                 return _marginY;
147             }
148
149             set
150             {
151                 _marginY = value;
152             }
153         }
154
155         public float Width
156         {
157             get
158             {
159                 return _width;
160             }
161
162             set
163             {
164                 _width = value;
165             }
166         }
167
168         public float Height
169         {
170             get
171             {
172                 return _height;
173             }
174
175             set
176             {
177                 _height = value;
178             }
179         }
180
181         public ImageView ShadowBorder
182         {
183             get
184             {
185                 return _shadowBorder;
186             }
187
188             set
189             {
190                 _shadowBorder = value;
191             }
192         }
193
194         public ImageView SpotLight
195         {
196             get
197             {
198                 return _spotLight;
199             }
200
201             set
202             {
203                 _spotLight = value;
204             }
205         }
206
207         public int FocusedItemID
208         {
209             get
210             {
211                 if (_focusedItem < 0)
212                 {
213                     _focusedItem = 0;
214                 }
215
216                 return _focusedItem;
217             }
218         }
219
220         // This override method is called automatically after the Control has been initialized.
221         // Any second phase initialization is done here.
222         public override void OnInitialize()
223         {
224             _itemSize = new Size(0.0f, 0.0f, 0.0f);
225             _gap = 0.0f;
226             _width = 0.0f;
227             _height = 0.0f;
228             _currentScrollPosition = 0.0f;
229             _itemCount = 0;
230             _focusedItem = -1;
231             _isFocused = false;
232             _marginX = 50.0f;
233             _marginY = 0.0f;
234             _offsetYFactor = 0.0f;
235             _offsetX = 0.0f;
236
237             _container = new View();
238             this.Add(_container);
239
240             _itemList = new List<View>();
241
242             this.ParentOrigin = Tizen.NUI.ParentOrigin.TopLeft;
243             this.AnchorPoint = Tizen.NUI.AnchorPoint.TopLeft;
244             this.WidthResizePolicy = ResizePolicyType.FillToParent;
245             this.HeightResizePolicy = ResizePolicyType.FillToParent;
246             this.Focusable = (true);
247
248             _container.ParentOrigin = Tizen.NUI.ParentOrigin.TopLeft;
249             _container.AnchorPoint = Tizen.NUI.AnchorPoint.TopLeft;
250             _container.WidthResizePolicy = ResizePolicyType.FillToParent;
251             _container.HeightResizePolicy = ResizePolicyType.FillToParent;
252
253             _stage = Stage.Instance;
254             _stageSize = _stage.Size;
255
256             _spotLightAnimation = new Animation(Constants.SpotLightDuration);
257             _focusTransitionAnimation = new Animation(Constants.FocusTransitionDuration);
258             _focusAnimation = new Animation(Constants.FocusDuration);
259             _focusAnimation.EndAction = Animation.EndActions.StopFinal;
260             _scrollAnimation = new Animation(Constants.ScrollDuration);
261             _scrollAnimation.EndAction = Animation.EndActions.StopFinal;\r
262 \r
263             //changed to internal\r
264             //EnableGestureDetection(Gesture.Type.Pan);
265         }
266
267         // This will be invoked automatically if an item/image is added to the ScrollContainer
268         public override void OnChildAdd(Actor actor)
269         {
270             View item = View.DownCast(actor);
271             //View item = actor as View;
272
273             if (item is View && item != _container)
274             {
275                 item.AnchorPoint = Tizen.NUI.AnchorPoint.BottomCenter;
276                 item.ParentOrigin = Tizen.NUI.ParentOrigin.BottomCenter;
277
278                 item.Size = _itemSize;
279                 item.Focusable = (true);
280                 item.Position = GetItemPosition(_itemCount, _currentScrollPosition);
281                 item.Name = _itemCount.ToString();
282
283                 _container.Add(item);
284                 _itemList.Add(item);
285
286                 _itemCount++;
287             }
288         }
289
290         // This will be invoked automatically if an item/image is removed from the ScrollContainer
291         public override void OnChildRemove(Actor actor)
292         {
293             View item = View.DownCast(actor);
294             //View item = actor as View;
295
296             if (item is View && item != _container)
297             {
298                 _container.Remove(item);
299
300                 _itemCount--;
301                 _itemList.Remove(item);
302             }
303         }
304
305         // This override function supports two dimensional keyboard navigation.
306         // This function returns the next keyboard focusable actor in ScrollContainer control towards the given direction.
307         public override View GetNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled)\r
308         {\r
309             if (direction == View.FocusDirection.Left)\r
310             {\r
311               return View.DownCast(FocusPrevious(loopEnabled));\r
312             }\r
313             else if (direction == View.FocusDirection.Right)\r
314             {\r
315               return View.DownCast(FocusNext(loopEnabled));\r
316             }\r
317             else\r
318             {\r
319               return View.DownCast(currentFocusedView);\r
320             }\r
321         }\r
322         \r
323         public override void OnFocusChangeCommitted(View commitedFocusableView)\r
324         {
325             Focus(_focusedItem);
326         }
327 \r
328 \r
329     // This override function is invoked before chosen focusable actor will be focused.\r
330     // This allows the application to preform any actions (i.e. Scroll and SpotLight animations) before the focus is actually moved to the chosen actor.\r
331 \r
332     // This override function is invoked whenever a pan gesture is detected on this control.\r
333     // Perform Scroll Animation based upon pan gesture velocity / speed.\r
334     /*public override void OnPan(PanGesture pan)\r
335     {\r
336       return;  //currently not used\r
337     }*/\r
338 \r
339     // This function returns current focused actor\r
340     public View GetCurrentFocusedActor()
341         {
342             if (_focusedItem < 0)
343             {
344                 _focusedItem = 0;
345             }
346
347             return _itemList[_focusedItem];
348         }
349
350         public void SetFocused(bool focused)
351         {
352             _isFocused = focused;
353
354             // Perform Focus animation if the ScrollContainer is not focused already
355             if (!_isFocused)
356             {
357                 Actor parent = _shadowBorder.Parent;
358                 if (parent)
359                 {
360                     parent.Remove(_shadowBorder);
361                 }
362
363                 parent = _spotLight.Parent;
364                 if (parent)
365                 {
366                     parent.Remove(_spotLight);
367                 }
368
369                 _focusTransitionAnimation.Clear();
370
371                 for (int i = 0; i < _itemList.Count; ++i)
372                 {
373                     Position targetPosition = GetItemPosition(i, _currentScrollPosition);
374
375                     _focusTransitionAnimation.AnimateTo(_itemList[i],  "Position", targetPosition, new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine));
376
377                     _focusTransitionAnimation.AnimateTo(_itemList[i], "Scale", new Size(1.0f, 1.0f, 1.0f),  new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine));
378                 }
379
380                 _focusTransitionAnimation.Play();
381             }
382             else
383             {
384                 Focus(_focusedItem);
385             }
386         }
387
388         // Obtain ID of first visible item/image on the screen of the ScrollContainer
389         private int GetFirstVisibleItemId()
390         {
391             int firstItemId = -1;
392
393             if (_isFocused)
394             {
395                 firstItemId = (int)Math.Floor((-1.0 * _currentScrollPosition + _marginX * 2.0f) / (_itemSize.Width + _gap));
396             }
397             else
398             {
399                 firstItemId = (int)Math.Floor(-1.0 * _currentScrollPosition / (_itemSize.Width + _gap));
400             }
401
402             if (firstItemId < 0)
403             {
404                 firstItemId = 0;
405             }
406
407             return firstItemId;
408         }
409
410         // Obtain ID of last visible item/image on the screen of the ScrollContainer
411         private int GetLastVisibleItemId()
412         {
413             int lastItemId = -1;
414
415             if (_isFocused)
416             {
417                 lastItemId = (int)Math.Ceiling(((_width - _currentScrollPosition - _marginX * 2.0f) / _itemSize.Width) - 1);
418             }
419             else
420             {
421                 lastItemId = (int)Math.Ceiling(((_width - _currentScrollPosition) / _itemSize.Width) - 1);
422             }
423
424             if (lastItemId >= _itemList.Count)
425             {
426
427                 lastItemId = _itemList.Count - 1;
428             }
429
430             return lastItemId;
431         }
432
433         // Obtain Next item/image (Right of the currently focused item) of the ScrollContainer
434         private Actor FocusNext(bool loopEnabled)
435         {
436             int nextItem = -1;
437
438             if (_focusedItem < GetFirstVisibleItemId() || _focusedItem > GetLastVisibleItemId())
439             {
440                 nextItem = GetFirstVisibleItemId();
441             }
442             else
443             {
444                 nextItem = _focusedItem + 1;
445             }
446
447             if (nextItem >= _itemList.Count)
448             {
449                 if (loopEnabled)
450                 {
451                     nextItem = 0;
452                 }
453                 else
454                 {
455                     nextItem = _itemList.Count - 1;
456                 }
457             }
458
459             _focusedItem = nextItem;
460             return _itemList[_focusedItem];
461         }
462
463         // Obtain Previous item/image (left of the currently focused item) of the ScrollContainer
464         private Actor FocusPrevious(bool loopEnabled)
465         {
466             int previousItem = -1;
467
468             if (_focusedItem < GetFirstVisibleItemId() || _focusedItem > GetLastVisibleItemId())
469             {
470                 previousItem = GetFirstVisibleItemId();
471             }
472             else
473             {
474                 previousItem = _focusedItem - 1;
475             }
476
477             if (previousItem < 0)
478             {
479                 if (loopEnabled)
480                 {
481                     previousItem = _itemList.Count - 1;
482                 }
483                 else
484                 {
485                     previousItem = 0;
486                 }
487             }
488
489             _focusedItem = previousItem;
490             return _itemList[_focusedItem];
491         }
492
493         // Perform ScrollAnimation on each item
494         private void Scroll(float amount, int baseItem)
495         {
496             float tagetScrollPosition = _currentScrollPosition + amount;
497             float totalItemSize = _itemList.Count * (_itemSize.Width + _gap) + _gap + (_marginX * 2.0f);
498
499             float maxScrollPosition = _width - totalItemSize;
500
501             if (tagetScrollPosition < maxScrollPosition)
502             {
503                 tagetScrollPosition = maxScrollPosition;
504             }
505
506             if (tagetScrollPosition > 0.0f)
507             {
508                 tagetScrollPosition = 0.0f;
509             }
510
511             _scrollAnimation.Clear();
512
513             for (int i = 0; i < _itemList.Count; ++i)
514             {
515                 Position targetPosition = GetItemPosition(i, tagetScrollPosition);
516
517                 _scrollAnimation.AnimateTo(_itemList[i], "Position", targetPosition, new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine));
518             }
519
520             _currentScrollPosition = tagetScrollPosition;
521             _scrollAnimation.Play();
522         }
523
524         // This function uses ItemId as next FocusedItem and preforms Scroll and SpotLight animations on that item.
525         private void Focus(int itemId)
526         {
527                 
528             if (itemId < 0)
529             {
530                 itemId = 0;
531             }
532             else if (itemId >= _itemList.Count)
533             {
534                 itemId = _itemList.Count - 1;
535             }
536
537             _itemList[itemId].Add(_shadowBorder);
538             _itemList[itemId].Add(_spotLight);
539
540             // Perform Spot Light animation
541             if (_focusedItem != itemId && _spotLight != null)
542             {
543                 _spotLightAnimation.Clear();
544                 _spotLightAnimation.AnimatePath(_spotLight, _circularPath, new Vector3(0.0f, 0.0f, 0.0f));
545                 _spotLightAnimation.Looping = true;
546                 _spotLightAnimation.Play();
547             }
548
549             _focusedItem = itemId;
550
551             Position itemPosition = GetItemPosition(_focusedItem, _currentScrollPosition);
552
553             _focusAnimation.Clear();
554
555             float relativeItemPositionX = itemPosition.X - _itemSize.Width * 0.5f + (_stageSize.Width * 0.5f) + _offsetX;
556             if (relativeItemPositionX < _marginX + _offsetX + _gap)
557             {
558                 float amount = _marginX + _offsetX + _gap - relativeItemPositionX;
559                 Scroll(amount, itemId + 1); // Perform Scroll animation
560             }
561             else if (relativeItemPositionX + _itemSize.Width + _gap + _marginX > _stageSize.Width)
562             {
563                 float amount = relativeItemPositionX + _marginX + _gap + _itemSize.Width - _stageSize.Width;
564                 Scroll(-amount, itemId - 1); // Perform Scroll animation
565             }
566             else
567             {
568                 // Perform animation when item is focused
569                 for (int i = 0; i < _itemList.Count; ++i)
570                 {
571                     Position targetPosition = GetItemPosition(i, _currentScrollPosition);
572
573                     _focusAnimation.AnimateTo(_itemList[i], "Position",targetPosition,  new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine) );
574                 }
575             }
576
577             for (int i = 0; i < _itemList.Count; ++i)
578             {
579                 // Perform scale animation on Focused item
580                 if (i == _focusedItem)
581                 {
582                     _focusAnimation.AnimateTo(_itemList[i],  "Scale", new Size(1.2f, 1.2f, 1.2f), new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine));
583                 }
584                 else
585                 {
586
587                     _focusAnimation.AnimateTo(_itemList[i], "Scale", new Size(1.0f, 1.0f, 1.0f), new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine) );
588                 }
589             }
590
591             _focusAnimation.Play();
592
593         }
594
595         // Calculate Position of any item/image of ScrollContainer
596         private Position GetItemPosition(int itemId, float scrollPosition)
597         {
598             if (_isFocused)
599             {
600                 // used (_itemSize.Width * 0.5f) because of AnchorPointCenter
601                 // used (_stageSize.Width * 0.5f) because of ParentOriginCenter
602                 if (_focusedItem > itemId)
603                 {
604                     float positionX = (_itemSize.Width * itemId) + (_gap * (itemId + 1)) + scrollPosition + (_itemSize.Width * 0.5f) - (_stageSize.Width * 0.5f);
605                     return new Position(positionX, -_itemSize.Height * _offsetYFactor, 0.0f);
606                 }
607                 else if (_focusedItem == itemId)
608                 {
609                     float positionX = (_itemSize.Width * itemId) + (_gap * (itemId + 1)) + scrollPosition + _marginX + (_itemSize.Width * 0.5f) - (_stageSize.Width * 0.5f);
610                     return new Position(positionX, -_itemSize.Height * _offsetYFactor, 0.0f);
611                 }
612                 else
613                 {
614                     float positionX = (_itemSize.Width * itemId) + (_gap * (itemId + 1)) + scrollPosition + _marginX * 2.0f + (_itemSize.Width * 0.5f) - (_stageSize.Width * 0.5f);
615                     return new Position(positionX, -_itemSize.Height * _offsetYFactor, 0.0f);
616                 }
617             }
618             else
619             {
620                 float positionX = (_itemSize.Width * itemId) + (_gap * (itemId + 1)) + scrollPosition + (_itemSize.Width * 0.5f) - (_stageSize.Width * 0.5f);
621                 return new Position(positionX, -_itemSize.Height * _offsetYFactor, 0.0f);
622             }
623         }
624
625
626     }
627
628 }
629