Release 8.0.0.15333
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / FlexibleView / GridLayoutManager.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.ComponentModel;
18
19 namespace Tizen.NUI.Components
20 {
21     /// <summary>
22     /// Layout collection of views in a grid.
23     /// </summary>
24     /// <since_tizen> 6 </since_tizen>
25     /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
26     [EditorBrowsable(EditorBrowsableState.Never)]
27     public class GridLayoutManager : LinearLayoutManager
28     {
29         private const int DEFAULT_SPAN_COUNT = -1;
30
31         private int mSpanCount = DEFAULT_SPAN_COUNT;
32
33         /// <summary>
34         /// Creates a GridLayoutManager with orientation. 
35         /// </summary>
36         /// <param name="spanCount">The number of columns or rows in the grid</param>
37         /// <param name="orientation">Layout orientation.Should be HORIZONTAL or VERTICAL</param>
38         /// <since_tizen> 6 </since_tizen>
39         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
40         [EditorBrowsable(EditorBrowsableState.Never)]
41         public GridLayoutManager(int spanCount, int orientation) : base(orientation)
42         {
43             mSpanCount = spanCount;
44         }
45
46         internal override void EnsureAnchorReady(FlexibleViewRecycler recycler, AnchorInfo anchorInfo, int itemDirection)
47         {
48             bool layingOutInPrimaryDirection = (itemDirection == LayoutState.ITEM_DIRECTION_TAIL);
49             int span = anchorInfo.Position % mSpanCount;
50             if (layingOutInPrimaryDirection)
51             {
52                 // choose span 0
53                 while (span > 0 && anchorInfo.Position > 0)
54                 {
55                     anchorInfo.Position--;
56                     span = anchorInfo.Position;
57                 }
58             }
59             else
60             {
61                 // choose the max span we can get. hopefully last one
62                 int indexLimit = ChildCount - 1;
63                 int pos = anchorInfo.Position;
64                 int bestSpan = span;
65                 while (pos < indexLimit)
66                 {
67                     int next = (pos + 1) % mSpanCount;
68                     if (next > bestSpan)
69                     {
70                         pos += 1;
71                         bestSpan = next;
72                     }
73                     else
74                     {
75                         break;
76                     }
77                 }
78                 anchorInfo.Position = pos;
79             }
80         }
81
82         /// <summary>
83         /// Retrieves a position that neighbor to current position by direction. 
84         /// </summary>
85         /// <param name="position">The anchor adapter position</param>
86         /// <param name="direction">The direction.</param>
87         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
88         [EditorBrowsable(EditorBrowsableState.Never)]
89         protected override int GetNextPosition(int position, FlexibleViewLayoutManager.Direction direction)
90         {
91             if (mOrientation == HORIZONTAL)
92             {
93                 switch (direction)
94                 {
95                     case FlexibleViewLayoutManager.Direction.Left:
96                         if (position >= mSpanCount)
97                         {
98                             return position - mSpanCount;
99                         }
100                         break;
101                     case FlexibleViewLayoutManager.Direction.Right:
102                         if (position < ItemCount - mSpanCount)
103                         {
104                             return position + mSpanCount;
105                         }
106                         break;
107                     case FlexibleViewLayoutManager.Direction.Up:
108                         if (position % mSpanCount > 0)
109                         {
110                             return position - 1;
111                         }
112                         break;
113                     case FlexibleViewLayoutManager.Direction.Down:
114                         if (position < ItemCount - 1 && (position % mSpanCount < mSpanCount - 1))
115                         {
116                             return position + 1;
117                         }
118                         break;
119                 }
120             }
121             else
122             {
123                 switch (direction)
124                 {
125                     case FlexibleViewLayoutManager.Direction.Left:
126                         if (position % mSpanCount > 0)
127                         {
128                             return position - 1;
129                         }
130                         break;
131                     case FlexibleViewLayoutManager.Direction.Right:
132                         if (position < ItemCount - 1 && (position % mSpanCount < mSpanCount - 1))
133                         {
134                             return position + 1;
135                         }
136                         break;
137                     case FlexibleViewLayoutManager.Direction.Up:
138                         if (position >= mSpanCount)
139                         {
140                             return position - mSpanCount;
141                         }
142                         break;
143                     case FlexibleViewLayoutManager.Direction.Down:
144                         if (position < ItemCount - mSpanCount)
145                         {
146                             return position + mSpanCount;
147                         }
148                         break;
149                 }
150             }
151
152             return NO_POSITION;
153         }
154
155         internal override void LayoutChunk(FlexibleViewRecycler recycler,
156             LayoutState layoutState, LayoutChunkResult result)
157         {
158             bool layingOutInPrimaryDirection =
159                 layoutState.ItemDirection == LayoutState.ITEM_DIRECTION_TAIL;
160
161             int count = mSpanCount;
162             for (int i = 0; i < count; i++)
163             {
164                 FlexibleViewViewHolder holder = layoutState.Next(recycler);
165                 if (holder == null)
166                 {
167                     result.Finished = true;
168                     return;
169                 }
170
171                 if (layingOutInPrimaryDirection)
172                     AddView(holder);
173                 else
174                     AddView(holder, 0);
175
176                 result.Consumed = mOrientationHelper.GetViewHolderMeasurement(holder);
177
178                 float left, top, width, height;
179                 if (mOrientation == VERTICAL)
180                 {
181                     width = (Width - PaddingLeft - PaddingRight) / count;
182                     height = result.Consumed;
183                     if (layoutState.LayoutDirection == LayoutState.LAYOUT_END)
184                     {
185                         left = PaddingLeft + width * i;
186                         top = layoutState.Offset;
187                     }
188                     else
189                     {
190                         left = PaddingLeft + width * (count - 1 - i);
191                         top = layoutState.Offset - height;
192                     }
193                     LayoutChild(holder, left, top, width, height);
194                 }
195                 else
196                 {
197                     width = result.Consumed;
198                     height = (Height - PaddingTop - PaddingBottom) / count;
199                     if (layoutState.LayoutDirection == LayoutState.LAYOUT_END)
200                     {
201                         top = PaddingTop + height * i;
202                         left = layoutState.Offset;
203                     }
204                     else
205                     {
206                         top = PaddingTop + height * (count - 1 - i);
207                         left = layoutState.Offset - width;
208                     }
209                     LayoutChild(holder, left, top, width, height);
210                 }
211             }
212         }
213
214
215     }
216 }