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