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