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