Add a prototype of CircularPagination (#1527)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Wearable / src / public / CircularPagination.cs
1 /*
2  * Copyright(c) 2020 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;
18 using System.Collections.Generic;
19 using System.ComponentModel;
20 using Tizen.NUI.BaseComponents;
21 using Tizen.NUI.Components;
22
23 namespace Tizen.NUI.Wearable
24 {
25     /// <summary>
26     /// CircularPagination shows the number of pages available and the currently active page.
27     /// Especially, CircularPagination provides indicators specific to wearable device.
28     /// </summary>
29     /// <since_tizen> 8 </since_tizen>
30     /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
31     [EditorBrowsable(EditorBrowsableState.Never)]
32     public class CircularPagination: Control
33     {
34         private CircularPaginationStyle circularPaginationStyle;
35
36         private VisualView container;
37
38         private List<ImageVisual> indicatorList = new List<ImageVisual>();
39
40         private bool isSymmetrical = true;
41         private int middleIndex = 9;
42         private int indicatorCount = 1;
43         private int leftIndicatorCount = 0;
44         private int rightIndicatorCount = 0;
45         private int selectedIndex = -1;
46         private bool isCenterImageSet = false; // When CenterIndicatorImageURL is set, this variable becomes true.
47         private bool isCurrentIndicatorCentered = false; // When the current indicator is the center one, this variable becomes true.
48         private bool isOddNumber = true;
49         private bool uninitializedLeftIndicator = true; // Need it when the indicators are asymmetry and the right indicator count is set earlier than left one.
50         private Animation selectAnimation = null;
51         private bool isNeedAnimation = false; // TODO : Animation will support using override function later.
52
53         Position2D[] oddArray = new Position2D[] { new Position2D(36, 74), new Position2D(47, 60), new Position2D(60, 47), new Position2D(74, 36),
54                                                    new Position2D(89, 26), new Position2D(105, 18), new Position2D(122, 11), new Position2D(139, 7),
55                                                    new Position2D(157, 4), new Position2D(175, 3), new Position2D(193, 4), new Position2D(211, 7),
56                                                    new Position2D(228, 11), new Position2D(245, 18), new Position2D(261, 26), new Position2D(276, 36),
57                                                    new Position2D(290, 47), new Position2D(303, 60), new Position2D(314, 73) };
58
59         Position2D[] evenArray = new Position2D[] { new Position2D(41, 67), new Position2D(53, 53), new Position2D(67, 41), new Position2D(81, 31),
60                                                    new Position2D(97, 22), new Position2D(113, 14), new Position2D(131, 9), new Position2D(148, 5),
61                                                    new Position2D(166, 3), new Position2D(184, 3), new Position2D(202, 5), new Position2D(220, 9),
62                                                    new Position2D(237, 14), new Position2D(253, 22), new Position2D(269, 31), new Position2D(283, 41),
63                                                    new Position2D(297, 53), new Position2D(309, 67) };
64
65         static CircularPagination() { }
66
67         /// <summary>
68         /// Creates a new instance of a CircularPagination.
69         /// </summary>
70         /// <since_tizen> 8 </since_tizen>
71         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
72         [EditorBrowsable(EditorBrowsableState.Never)]
73         public CircularPagination() : base()
74         {
75             Initialize();
76         }
77
78         /// <summary>
79         /// Creates a new instance of a CircularPagination using style.
80         /// </summary>
81         /// <since_tizen> 8 </since_tizen>
82         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
83         [EditorBrowsable(EditorBrowsableState.Never)]
84         public CircularPagination(string style) : base(style)
85         {
86             Initialize();
87         }
88
89         /// <summary>
90         /// Creates a new instance of a CircularPagination using style.
91         /// </summary>
92         /// <since_tizen> 8 </since_tizen>
93         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
94         [EditorBrowsable(EditorBrowsableState.Never)]
95         public CircularPagination(CircularPaginationStyle style) : base(style)
96         {
97             Initialize();
98         }
99
100         /// <summary>
101         /// Gets or sets the size of the indicator.
102         /// </summary>
103         /// <since_tizen> 8 </since_tizen>
104         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
105         [EditorBrowsable(EditorBrowsableState.Never)]
106         public Size IndicatorSize
107         {
108             get
109             {
110                 return circularPaginationStyle?.IndicatorSize;
111             }
112             set
113             {
114                 if (value == null || circularPaginationStyle == null)
115                 {
116                     return;
117                 }
118                 circularPaginationStyle.IndicatorSize = value;
119                 UpdateVisual();
120             }
121         }
122
123         /// <summary>
124         /// Gets or sets the background resource of indicator.
125         /// </summary>
126         /// <since_tizen> 8 </since_tizen>
127         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
128         [EditorBrowsable(EditorBrowsableState.Never)]
129         public Selector<string> IndicatorImageURL
130         {
131             get
132             {
133                 return circularPaginationStyle?.IndicatorImageURL;
134             }
135             set
136             {
137                 if (value == null || circularPaginationStyle == null)
138                 {
139                     return;
140                 }
141                 circularPaginationStyle.IndicatorImageURL = value;
142                 UpdateVisual();
143             }
144         }
145
146         /// <summary>
147         /// Gets or sets the background resource of the center indicator.
148         /// </summary>
149         /// <since_tizen> 8 </since_tizen>
150         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
151         [EditorBrowsable(EditorBrowsableState.Never)]
152         public Selector<string> CenterIndicatorImageURL
153         {
154             get
155             {
156                 if (isCenterImageSet)
157                 {
158                     return circularPaginationStyle?.CenterIndicatorImageURL;
159                 }
160                 else
161                 {
162                     Log.Info("NUI", "CenterIndicatorImageURL is not set yet. \n");
163                     return "";
164                 }
165
166             }
167             set
168             {
169                 if (value == null || circularPaginationStyle == null)
170                 {
171                     return;
172                 }
173                 circularPaginationStyle.CenterIndicatorImageURL = value;
174                 isCenterImageSet = true;
175                 UpdateVisual();
176             }
177         }
178
179         /// <summary>
180         /// Checks whether the indicators are symmetrical or not.
181         ///
182         /// The default value is true.
183         /// If the value is true, the user just can set IndicatorCount.
184         /// If false, the user should set both the number of Left Indicators and the number of Right Indicators.
185         /// Please refer to LeftIndicatorCount and RightIndicatorCount.
186         /// </summary>
187         /// <since_tizen> 8 </since_tizen>
188         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
189         [EditorBrowsable(EditorBrowsableState.Never)]
190         public bool IsSymmetrical
191         {
192             get
193             {
194                 return isSymmetrical;
195             }
196             set
197             {
198                 if (isSymmetrical == value)
199                 {
200                     return;
201                 }
202                 if (value == false)
203                 {
204                     CreateIndicator(middleIndex);
205                 }
206
207                 isSymmetrical = value;
208                 UpdateContainer();
209                 UpdateVisual();
210             }
211         }
212
213
214         /// <summary>
215         /// Gets or sets the number of the pages/indicators.
216         ///
217         /// This value is for symmetrical indicators.
218         /// </summary>
219         /// <since_tizen> 8 </since_tizen>
220         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
221         [EditorBrowsable(EditorBrowsableState.Never)]
222         public int IndicatorCount
223         {
224             get
225             {
226                 return indicatorCount;
227             }
228             set
229             {
230                 if (indicatorCount == value || indicatorCount < 0)
231                 {
232                     return;
233                 }
234                 if (value % 2 == 1) // Odd number
235                 {
236                     isOddNumber = true;
237                 }
238                 else // Even number
239                 {
240                     isOddNumber = false;
241                 }
242
243                 if (indicatorCount < value)
244                 {
245                     int arrayIndex = 0;
246                     if (isOddNumber)
247                     {
248                         arrayIndex = (19 - value) / 2;
249                     }
250                     else
251                     {
252                         arrayIndex = (18 - value) / 2;
253                     }
254
255                     for (int i = indicatorCount; i <= value; i++)
256                     {
257                         CreateIndicator( arrayIndex );
258                         arrayIndex++;
259                     }
260
261                     // If selectedIndex is not set yet, the default value is middle index.
262                     if (selectedIndex == -1)
263                     {
264                         selectedIndex = value / 2;
265                         SelectIn(indicatorList[selectedIndex]);
266                     }
267                 }
268                 else
269                 {
270                     for (int i = value; i < indicatorCount; i++)
271                     {
272                         ImageVisual indicator = indicatorList[i];
273                         container.RemoveVisual("Indicator" + i);
274                     }
275                     indicatorList.RemoveRange(value, indicatorCount - value);
276
277                     if (selectedIndex >= value)
278                     {
279                         selectedIndex = 0;
280                         SelectIn(indicatorList[selectedIndex]);
281                     }
282                 }
283                 indicatorCount = value;
284
285                 UpdateContainer();
286             }
287         }
288
289         /// <summary>
290         /// Gets or sets the number of the left pages/indicators.
291         ///
292         /// This value can be set when IsSymmetrical API is false.
293         /// </summary>
294         /// <since_tizen> 8 </since_tizen>
295         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
296         [EditorBrowsable(EditorBrowsableState.Never)]
297         public int LeftIndicatorCount
298         {
299             get
300             {
301                 return leftIndicatorCount;
302             }
303             set
304             {
305                 if (isSymmetrical == true)
306                 {
307                     Log.Info("NUI", "This variable is not for symmetric pagination. \n");
308                     isSymmetrical = false;
309                     //return;
310                 }
311                 if (leftIndicatorCount == value || leftIndicatorCount < 0 || leftIndicatorCount > 9)
312                 {
313                     return;
314                 }
315
316                 isOddNumber = true;
317
318                 if (leftIndicatorCount < value)
319                 {
320                     for (int i = (middleIndex - value); i < (middleIndex - leftIndicatorCount); i++)
321                     {
322                         CreateIndicator( i );
323                     }
324                 }
325                 else
326                 {
327                     for (int i = 0; i < (leftIndicatorCount - value); i++)
328                     {
329                         ImageVisual indicator = indicatorList[i];
330                         container.RemoveVisual("Indicator" + i);
331                     }
332                     indicatorList.RemoveRange(0, (leftIndicatorCount - value)); // LeftIndicator starts from index 0.
333
334                     if (selectedIndex >= ( value + rightIndicatorCount ))
335                     {
336                         selectedIndex--;
337                         SelectIn(indicatorList[selectedIndex]);
338                     }
339                     else if (selectedIndex == 0)
340                     {
341                         selectedIndex++;
342                         SelectIn(indicatorList[selectedIndex]);
343                     }
344                 }
345                 leftIndicatorCount = value;
346                 indicatorCount = leftIndicatorCount + rightIndicatorCount + 1;
347
348                 // When RightIndicatorCount is set before, then selectedIndex should be updated using the current LeftIndicatorCount.
349                 if (uninitializedLeftIndicator && selectedIndex == 0)
350                 {
351                     selectedIndex = leftIndicatorCount;
352                 }
353                 uninitializedLeftIndicator = false;
354
355                 UpdateContainer();
356                 UpdateAsymmetry();
357             }
358         }
359
360         /// <summary>
361         /// Gets or sets the number of the right pages/indicators.
362         ///
363         /// This value can be set when IsSymmetrical API is false.
364         /// </summary>
365         /// <since_tizen> 8 </since_tizen>
366         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
367         [EditorBrowsable(EditorBrowsableState.Never)]
368         public int RightIndicatorCount
369         {
370             get
371             {
372                 return rightIndicatorCount;
373             }
374             set
375             {
376                 if (isSymmetrical == true)
377                 {
378                     Log.Info("NUI", "This variable is not for symmetric pagination. \n");
379                     isSymmetrical = false;
380                     //return;
381                 }
382                 if (rightIndicatorCount == value || rightIndicatorCount < 0 || rightIndicatorCount > 9)
383                 {
384                     return;
385                 }
386
387                 isOddNumber = true;
388
389                 if (rightIndicatorCount < value)
390                 {
391                     for (int i = (middleIndex + rightIndicatorCount + 1); i <= (middleIndex + value); i++)
392                     {
393                         CreateIndicator( i );
394                     }
395                 }
396                 else
397                 {
398                     for (int i = (leftIndicatorCount + value + 1); i < (leftIndicatorCount + rightIndicatorCount); i++)
399                     {
400                         ImageVisual indicator = indicatorList[i];
401                         container.RemoveVisual("Indicator" + i);
402                     }
403                     indicatorList.RemoveRange((leftIndicatorCount + value), (rightIndicatorCount - value));
404
405                     if (selectedIndex >= (leftIndicatorCount + rightIndicatorCount))
406                     {
407                         selectedIndex--;
408                         SelectIn(indicatorList[selectedIndex]);
409                     }
410                 }
411                 rightIndicatorCount = value;
412                 indicatorCount = leftIndicatorCount + rightIndicatorCount + 1;
413
414                 UpdateContainer();
415                 UpdateAsymmetry();
416             }
417         }
418
419         /// <summary>
420         /// Gets or sets the index of the select indicator.
421         ///
422         /// If no value is set, the default value is the center indicator.
423         /// </summary>
424         /// <since_tizen> 8 </since_tizen>
425         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
426         [EditorBrowsable(EditorBrowsableState.Never)]
427         public int SelectedIndex
428         {
429             get
430             {
431                 return selectedIndex;
432             }
433             set
434             {
435                 if (selectedIndex == value)
436                 {
437                     return;
438                 }
439
440                 // TODO : Here it needs to add virtual function for Animation.
441
442                 if (selectedIndex >= 0)
443                 {
444                     if ( (isSymmetrical && selectedIndex < indicatorCount) ||
445                          (!isSymmetrical && selectedIndex <= (middleIndex + rightIndicatorCount) ) )
446                     {
447                         CheckCenterIndicator(selectedIndex);
448                         SelectOut(indicatorList[selectedIndex]);
449                     }
450                 }
451                 selectedIndex = value;
452                 if (selectedIndex >= 0)
453                 {
454                     if ( (isSymmetrical && selectedIndex < indicatorCount) ||
455                          (!isSymmetrical && selectedIndex <= (middleIndex + rightIndicatorCount) ) )
456                     {
457                         CheckCenterIndicator(selectedIndex);
458                         SelectIn(indicatorList[selectedIndex]);
459                     }
460                 }
461             }
462         }
463
464         /// <summary>
465         /// Retrieves the position of a indicator by index.
466         /// </summary>
467         /// <param name="index">Indicator index</param>
468         /// <returns>The position of a indicator by index</returns>
469         /// <since_tizen> 8 </since_tizen>
470         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
471         [EditorBrowsable(EditorBrowsableState.Never)]
472         public Position GetIndicatorPosition(int index)
473         {
474             if (index < 0 || index >= indicatorList.Count)
475             {
476                 return null;
477             }
478             return new Position(indicatorList[index].Position.X, indicatorList[index].Position.Y);
479         }
480
481         /// <summary>
482         /// Sets the position of a indicator by index.
483         /// </summary>
484         /// <param name="index">Indicator index</param>
485         /// <param name="position">The position of a indicator by index</param>
486         /// <since_tizen> 8 </since_tizen>
487         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
488         [EditorBrowsable(EditorBrowsableState.Never)]
489         public virtual void SetIndicatorPosition(int index, Position position)
490         {
491             // Update odd / even Array and List by each converted index.
492             if (isOddNumber)
493             {
494                 if (isSymmetrical)
495                 {
496                     oddArray[(middleIndex - (indicatorCount / 2) + index)] = position;
497                 }
498                 else // IsSymmetrical is false and it means the number of left indicators is different from that of right ones.
499                 {
500                     oddArray[(middleIndex - leftIndicatorCount) + index] = position;
501                 }
502                 indicatorList[index].Position.X = position.X;
503                 indicatorList[index].Position.Y = position.Y;
504             }
505             else // Only symmetry circular pagination can be even number.
506             {
507                 evenArray[IndicatorCount/2 + index - 1] = position;
508                 indicatorList[index].Position.X = position.X;
509                 indicatorList[index].Position.Y = position.Y;
510             }
511             UpdateVisual();
512         }
513
514         private void CreateSelectAnimation()
515         {
516             if (selectAnimation == null)
517             {
518                 selectAnimation = new Animation(250);
519             }
520         }
521
522         /// <summary>
523         /// You can override it to do your select out operation.
524         /// </summary>
525         /// <param name="selectOutIndicator">The indicator will be selected out</param>
526         /// <since_tizen> 8 </since_tizen>
527         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
528         [EditorBrowsable(EditorBrowsableState.Never)]
529         protected virtual void SelectOut(VisualMap selectOutIndicator)
530         {
531             if (!(selectOutIndicator is ImageVisual visual)) return;
532             if (isCurrentIndicatorCentered)
533             {
534                 visual.URL = circularPaginationStyle.CenterIndicatorImageURL.Normal;
535             }
536             else
537             {
538                 visual.URL = circularPaginationStyle.IndicatorImageURL.Normal;
539             }
540         }
541
542         /// <summary>
543         /// You can override it to do your select in operation.
544         /// </summary>
545         /// <param name="selectInIndicator">The indicator will be selected in</param>
546         /// <since_tizen> 8 </since_tizen>
547         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
548         [EditorBrowsable(EditorBrowsableState.Never)]
549         protected virtual void SelectIn(VisualMap selectInIndicator)
550         {
551             if (!(selectInIndicator is ImageVisual visual)) return;
552             if (isCurrentIndicatorCentered)
553             {
554                 visual.URL = circularPaginationStyle.CenterIndicatorImageURL.Selected;
555             }
556             else
557             {
558                 visual.URL = circularPaginationStyle.IndicatorImageURL.Selected;
559             }
560         }
561
562         /// <summary>
563         /// you can override it to create your own default style.
564         /// </summary>
565         /// <since_tizen> 8 </since_tizen>
566         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
567         [EditorBrowsable(EditorBrowsableState.Never)]
568         protected override ViewStyle GetViewStyle()
569         {
570             return new CircularPaginationStyle();
571         }
572
573         /// <summary>
574         /// you can override it to clean-up your own resources.
575         /// </summary>
576         /// <param name="type">DisposeTypes</param>
577         /// <since_tizen> 8 </since_tizen>
578         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
579         [EditorBrowsable(EditorBrowsableState.Never)]
580         protected override void Dispose(DisposeTypes type)
581         {
582             if (disposed)
583             {
584                 return;
585             }
586
587             if (type == DisposeTypes.Explicit)
588             {
589                 if (selectAnimation != null)
590                 {
591                     if (selectAnimation.State == Animation.States.Playing)
592                     {
593                         selectAnimation.Stop();
594                     }
595                     selectAnimation.Dispose();
596                     selectAnimation = null;
597                 }
598
599                 container.RemoveAll();
600                 indicatorList.Clear();
601
602                 this.Remove(container);
603                 container.Dispose();
604                 container = null;
605             }
606
607             base.Dispose(type);
608         }
609
610         private void Initialize()
611         {
612             circularPaginationStyle = Style as CircularPaginationStyle;
613             if (circularPaginationStyle == null)
614             {
615                 throw new Exception("CircularPagination style is null.");
616             }
617
618             container = new VisualView()
619             {
620                 Name = "Container",
621                 ParentOrigin = Tizen.NUI.ParentOrigin.TopLeft,
622                 PivotPoint = Tizen.NUI.PivotPoint.TopLeft,
623                 PositionUsesPivotPoint = true,
624             };
625             this.Add(container);
626         }
627
628         // The parameter, index, is for the index of either oddArray or evenArray.
629         private void CreateIndicator(int index)
630         {
631             if (circularPaginationStyle == null)
632             {
633                 return;
634             }
635
636             ImageVisual indicator = new ImageVisual
637             {
638                 URL = circularPaginationStyle.IndicatorImageURL.Normal,
639                 Size = new Size2D((int)circularPaginationStyle.IndicatorSize.Width, (int)circularPaginationStyle.IndicatorSize.Height)
640             };
641
642             if (isOddNumber)
643             {
644                 indicator.Position = oddArray[index];
645             }
646             else
647             {
648                 indicator.Position = evenArray[index];
649             }
650
651             container.AddVisual("Indicator" + indicatorList.Count, indicator);
652             indicatorList.Add(indicator);
653         }
654
655         private void CheckCenterIndicator(int index)
656         {
657             if (isCenterImageSet &&
658                 (isSymmetrical && (index == indicatorCount / 2)) ||
659                 (!isSymmetrical && (index == leftIndicatorCount)) )
660             {
661                 isCurrentIndicatorCentered  = true;
662             }
663             else
664             {
665                 isCurrentIndicatorCentered = false;
666             }
667         }
668
669         private void UpdateContainer()
670         {
671             if (circularPaginationStyle == null)
672             {
673                 return;
674             }
675             if (indicatorList.Count > 0)
676             {
677                 container.SizeWidth = (circularPaginationStyle.IndicatorSize.Width) * indicatorList.Count;
678             }
679             else
680             {
681                 container.SizeWidth = 0;
682             }
683             container.SizeHeight = circularPaginationStyle.IndicatorSize.Height;
684         }
685
686         private void UpdateVisual()
687         {
688             if (null == circularPaginationStyle.IndicatorSize) return;
689             if (null == circularPaginationStyle.IndicatorImageURL) return;
690             if (indicatorCount < 0) return;
691
692             for (int i = 0; i < indicatorList.Count; i++)
693             {
694                 ImageVisual indicator = indicatorList[i];
695                 indicator.Size = new Size2D((int)circularPaginationStyle.IndicatorSize.Width, (int)circularPaginationStyle.IndicatorSize.Height);
696
697                 CheckCenterIndicator(i);
698
699                 if (i == selectedIndex)
700                 {
701                     // If the center image is set before, then should update the center visual separately.
702                     if (isCurrentIndicatorCentered)
703                     {
704                         indicator.URL = circularPaginationStyle.CenterIndicatorImageURL.Selected;
705                     }
706                     else
707                     {
708                         indicator.URL = circularPaginationStyle.IndicatorImageURL.Selected;
709                     }
710                 }
711                 else
712                 {
713                     // If the center image is set before, then should update the center visual separately.
714                     if (isCurrentIndicatorCentered)
715                     {
716                         indicator.URL = circularPaginationStyle.CenterIndicatorImageURL.Normal;
717                     }
718                     else
719                     {
720                         indicator.URL = circularPaginationStyle.IndicatorImageURL.Normal;
721                     }
722                 }
723
724                 if (isOddNumber)
725                 {
726                     if (isSymmetrical)
727                     {
728                         indicator.Position = oddArray[middleIndex - (indicatorCount / 2) + i];
729                     }
730                     else
731                     {
732                         indicator.Position = oddArray[(middleIndex - leftIndicatorCount) + i];
733                     }
734
735                 }
736                 else
737                 {
738                     indicator.Position = evenArray[IndicatorCount/2 + i - 1];
739                 }
740             }
741         }
742
743         private void UpdateAsymmetry()
744         {
745             if (null == circularPaginationStyle.IndicatorSize) return;
746             if (null == circularPaginationStyle.IndicatorImageURL) return;
747
748             int listCount = indicatorList.Count;
749
750             for (int i = 0; i < listCount; i++)
751             {
752                 container.RemoveVisual("Indicator" + i);
753             }
754             container.RemoveAll();
755             indicatorList.Clear();
756
757             for (int i = 0; i < listCount; i++)
758             {
759                 ImageVisual newOne = new ImageVisual
760                 {
761                     Size = new Size2D((int)circularPaginationStyle.IndicatorSize.Width, (int)circularPaginationStyle.IndicatorSize.Height),
762                     Position = oddArray[i + (middleIndex - leftIndicatorCount)]
763                 };
764
765                 if (isCenterImageSet && !isSymmetrical && (i == leftIndicatorCount))
766                 {
767                     newOne.URL = circularPaginationStyle.CenterIndicatorImageURL.Normal;
768                 }
769                 else
770                 {
771                     newOne.URL = circularPaginationStyle.IndicatorImageURL.Normal;
772                 }
773                 container.AddVisual("Indicator" + i, newOne);
774                 indicatorList.Add(newOne);
775             }
776
777             // If selectedIndex is not set yet, the default value is middle index.
778             if (selectedIndex == -1)
779             {
780                 selectedIndex = leftIndicatorCount;
781             }
782
783             if (isCenterImageSet && (selectedIndex == leftIndicatorCount))
784             {
785                 indicatorList[selectedIndex].URL = circularPaginationStyle.CenterIndicatorImageURL.Selected;
786             }
787             else
788             {
789                 indicatorList[selectedIndex].URL = circularPaginationStyle.IndicatorImageURL.Selected;
790             }
791         }
792     }
793 }