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