[NUI] Fixed svace issues
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / RecyclerView / LinearRecycleLayoutManager.cs
1 /* Copyright (c) 2020 Samsung Electronics Co., Ltd.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  *
15  */
16 using System;
17 using Tizen.NUI.BaseComponents;
18 using System.Collections.Generic;
19 using System.ComponentModel;
20
21 namespace Tizen.NUI.Components
22 {
23     /// <summary>
24     /// [Draft] This class implements a linear box layout.
25     /// </summary>
26     /// <since_tizen> 8 </since_tizen>
27     /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
28     [EditorBrowsable(EditorBrowsableState.Never)]
29     public class LinearRecycleLayoutManager : RecycleLayoutManager
30     {
31         private int firstVisibleItemIndex = -1;
32         private int lastVisibleItemIndex = -1;
33
34         private bool IsItemVisible(float scrollPosition, RecycleItem item)
35         {
36             bool result = false;
37             View list = Container.GetParent() as View;
38             if (list == null)
39             {
40                 return result;
41             }
42
43             Vector2 visibleArea = new Vector2( Math.Abs(scrollPosition), 
44                 Math.Abs(scrollPosition) + (LayoutOrientation == Orientation.Horizontal?
45                                                 list.Size.Width:list.Size.Height)
46             );
47
48             float firstCheckPoint = LayoutOrientation == Orientation.Horizontal? item.Position.X:item.Position.Y;
49             float secondCheckPoint = LayoutOrientation == Orientation.Horizontal? 
50                                         firstCheckPoint + item.Size.Width:
51                                         firstCheckPoint + item.Size.Height;
52
53             // Tizen.Log.Error("NUI", "[1p] "+visibleArea.X+ " =< "+firstCheckPoint+" =< "+visibleArea.Y+" ==== \n");
54             // Tizen.Log.Error("NUI", "[2p] "+visibleArea.X+ " =< "+secondCheckPoint+" =< "+visibleArea.Y+" ==== \n");
55
56             result = (firstCheckPoint >= visibleArea.X && firstCheckPoint <= visibleArea.Y) || (secondCheckPoint >= visibleArea.X && secondCheckPoint <= visibleArea.Y);
57
58             return result;
59         }
60
61         /// <summary>
62         /// This is called to find out where items are lain out according to current scroll position.
63         /// </summary>
64         /// <param name="scrollPosition">Scroll position which is calculated by ScrollableBase</param>
65         /// <since_tizen> 8 </since_tizen>
66         /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
67         public override void Layout(float scrollPosition)
68         {
69             firstVisibleItemIndex = -1;
70             lastVisibleItemIndex = -1;
71
72             RecycleItem previousItem = null;
73
74             for(int i = 0 ; i < Container.Children.Count ; i++)
75             {
76                 RecycleItem item = Container.Children[i] as RecycleItem;
77
78                 if(previousItem != null && item != null)
79                 {
80                     item.Position = LayoutOrientation == Orientation.Horizontal?
81                         new Position(
82                             previousItem.Position.X + (previousItem.CurrentSize.Width != 0 ?
83                                                             previousItem.CurrentSize.Width:
84                                                             previousItem.Size.Width),
85                             item.PositionY
86                         ):
87                         new Position(
88                             item.PositionX,
89                             previousItem.Position.Y + (previousItem.CurrentSize.Height != 0 ? 
90                                                             previousItem.CurrentSize.Height:
91                                                             previousItem.Size.Height)
92                         );
93                 }
94
95                 bool isVisible = IsItemVisible(scrollPosition, item);
96
97                 if(isVisible)
98                 {
99                     firstVisibleItemIndex = firstVisibleItemIndex == -1? i : firstVisibleItemIndex;
100                     lastVisibleItemIndex = i;
101                 }
102
103                 previousItem = item;
104
105                 // Tizen.Log.Error("NUI","["+item.DataIndex+"] "+item.Position.Y+" ==== \n");
106             }
107
108             if(StepSize == 0)
109             {
110                 StepSize = LayoutOrientation == Orientation.Horizontal?ItemSize.Width:ItemSize.Height;
111             }
112         }
113
114         /// <summary>
115         /// This is called to find out how much container size can be.
116         /// </summary>
117         /// <since_tizen> 8 </since_tizen>
118         /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
119         [EditorBrowsable(EditorBrowsableState.Never)]
120         public override float CalculateLayoutOrientationSize()
121         {
122             return StepSize * DataCount;
123         }
124
125         /// <summary>
126         /// This is called to find out which items should be recycled according to current scroll position.
127         /// </summary>
128         /// <param name="scrollPosition">Scroll position which is calculated by ScrollableBase</param>
129         /// <returns>List of RecycleItems which should be recycled.</returns>
130         /// <since_tizen> 8 </since_tizen>
131         /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
132         public override List<RecycleItem> Recycle(float scrollPosition)
133         {
134             List<RecycleItem> result = new List<RecycleItem>();
135           
136             bool checkFront = (PrevScrollPosition - scrollPosition) > 0;
137
138             if(checkFront)
139             {
140                 if(firstVisibleItemIndex > 3)
141                 {
142                     // Too many item is in front!!! move first item to back!!!!
143                     RecycleItem target = Container.Children[0] as RecycleItem;
144                     if (target != null)
145                     {
146                         target.DataIndex = target.DataIndex + Container.Children.Count;
147                         target.SiblingOrder = Container.Children.Count - 1;
148
149                         result.Add(target);
150                     }
151                 }
152             }
153             else
154             {
155                 if(lastVisibleItemIndex < Container.Children.Count - 3)
156                 {
157                     RecycleItem prevFirstItem = Container.Children[0] as RecycleItem;
158                     RecycleItem target = Container.Children[Container.Children.Count - 1] as RecycleItem;
159                     if (prevFirstItem != null && target != null)
160                     {
161                         target.Position = new Position(
162                             LayoutOrientation == Orientation.Horizontal ? (prevFirstItem.Position.X - target.Size.Width) : prevFirstItem.Position.X,
163                             LayoutOrientation == Orientation.Horizontal ? prevFirstItem.Position.Y : (prevFirstItem.Position.Y - target.Size.Height)
164                         );
165                         target.DataIndex = target.DataIndex - Container.Children.Count;
166                         target.SiblingOrder = 0;
167
168                         result.Add(target);
169                     }
170                 }
171             }
172
173             PrevScrollPosition = scrollPosition;
174
175             return result;
176         }
177
178         /// <summary>
179         /// Adjust scrolling position by own scrolling rules.
180         /// </summary>
181         /// <param name="scrollPosition">Scroll position which is calculated by ScrollableBase</param>
182         /// <since_tizen> 8 </since_tizen>
183         /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
184         public override float CalculateCandidateScrollPosition(float scrollPosition)
185         {
186             return scrollPosition;
187         }
188
189         public override View RequestNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled)
190         {
191             View nextFocusedView = null;
192             int targetSibling = -1;
193             bool isHorizontal = LayoutOrientation == Orientation.Horizontal;
194
195             switch(direction)
196             {
197                 case View.FocusDirection.Left :
198                 {
199                     targetSibling = isHorizontal ? currentFocusedView.SiblingOrder - 1 : targetSibling;
200                     break;
201                 }
202                 case View.FocusDirection.Right :
203                 {
204                     targetSibling = isHorizontal ? currentFocusedView.SiblingOrder + 1 : targetSibling;
205                     break;
206                 }
207                 case View.FocusDirection.Up :
208                 {
209                     targetSibling = isHorizontal ? targetSibling : currentFocusedView.SiblingOrder - 1;
210                     break;
211                 }
212                 case View.FocusDirection.Down :
213                 {
214                     targetSibling = isHorizontal ? targetSibling : currentFocusedView.SiblingOrder + 1;
215                     break;
216                 }
217             }
218
219             if(targetSibling > -1 && targetSibling < Container.Children.Count)
220             {
221                 RecycleItem candidate = Container.Children[targetSibling] as RecycleItem;
222                 if(candidate != null && candidate.DataIndex >= 0 && candidate.DataIndex < DataCount)
223                 {
224                     nextFocusedView = candidate;
225                 }
226             }
227
228             return nextFocusedView;
229         }
230     }
231 }