[NUI] Update CircularPagination opacity (#1573)
[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             visual.Opacity = 0.5f;
541         }
542
543         /// <summary>
544         /// You can override it to do your select in operation.
545         /// </summary>
546         /// <param name="selectInIndicator">The indicator will be selected in</param>
547         /// <since_tizen> 8 </since_tizen>
548         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
549         [EditorBrowsable(EditorBrowsableState.Never)]
550         protected virtual void SelectIn(VisualMap selectInIndicator)
551         {
552             if (!(selectInIndicator is ImageVisual visual)) return;
553             if (isCurrentIndicatorCentered)
554             {
555                 visual.URL = circularPaginationStyle.CenterIndicatorImageURL.Selected;
556             }
557             else
558             {
559                 visual.URL = circularPaginationStyle.IndicatorImageURL.Selected;
560             }
561             visual.Opacity = 1.0f;
562         }
563
564         /// <summary>
565         /// you can override it to create your own default style.
566         /// </summary>
567         /// <since_tizen> 8 </since_tizen>
568         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
569         [EditorBrowsable(EditorBrowsableState.Never)]
570         protected override ViewStyle GetViewStyle()
571         {
572             return new CircularPaginationStyle();
573         }
574
575         /// <summary>
576         /// you can override it to clean-up your own resources.
577         /// </summary>
578         /// <param name="type">DisposeTypes</param>
579         /// <since_tizen> 8 </since_tizen>
580         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
581         [EditorBrowsable(EditorBrowsableState.Never)]
582         protected override void Dispose(DisposeTypes type)
583         {
584             if (disposed)
585             {
586                 return;
587             }
588
589             if (type == DisposeTypes.Explicit)
590             {
591                 if (selectAnimation != null)
592                 {
593                     if (selectAnimation.State == Animation.States.Playing)
594                     {
595                         selectAnimation.Stop();
596                     }
597                     selectAnimation.Dispose();
598                     selectAnimation = null;
599                 }
600
601                 container.RemoveAll();
602                 indicatorList.Clear();
603
604                 this.Remove(container);
605                 container.Dispose();
606                 container = null;
607             }
608
609             base.Dispose(type);
610         }
611
612         private void Initialize()
613         {
614             circularPaginationStyle = Style as CircularPaginationStyle;
615             if (circularPaginationStyle == null)
616             {
617                 throw new Exception("CircularPagination style is null.");
618             }
619
620             container = new VisualView()
621             {
622                 Name = "Container",
623                 ParentOrigin = Tizen.NUI.ParentOrigin.TopLeft,
624                 PivotPoint = Tizen.NUI.PivotPoint.TopLeft,
625                 PositionUsesPivotPoint = true,
626             };
627             this.Add(container);
628         }
629
630         // The parameter, index, is for the index of either oddArray or evenArray.
631         private void CreateIndicator(int index)
632         {
633             if (circularPaginationStyle == null)
634             {
635                 return;
636             }
637
638             ImageVisual indicator = new ImageVisual
639             {
640                 URL = circularPaginationStyle.IndicatorImageURL.Normal,
641                 Size = new Size2D((int)circularPaginationStyle.IndicatorSize.Width, (int)circularPaginationStyle.IndicatorSize.Height),
642                 Opacity = 0.5f,
643             };
644
645             if (isOddNumber)
646             {
647                 indicator.Position = oddArray[index];
648             }
649             else
650             {
651                 indicator.Position = evenArray[index];
652             }
653
654             container.AddVisual("Indicator" + indicatorList.Count, indicator);
655             indicatorList.Add(indicator);
656         }
657
658         private void CheckCenterIndicator(int index)
659         {
660             if (isCenterImageSet &&
661                 (isSymmetrical && (index == indicatorCount / 2)) ||
662                 (!isSymmetrical && (index == leftIndicatorCount)) )
663             {
664                 isCurrentIndicatorCentered  = true;
665             }
666             else
667             {
668                 isCurrentIndicatorCentered = false;
669             }
670         }
671
672         private void UpdateContainer()
673         {
674             if (circularPaginationStyle == null)
675             {
676                 return;
677             }
678             if (indicatorList.Count > 0)
679             {
680                 container.SizeWidth = (circularPaginationStyle.IndicatorSize.Width) * indicatorList.Count;
681             }
682             else
683             {
684                 container.SizeWidth = 0;
685             }
686             container.SizeHeight = circularPaginationStyle.IndicatorSize.Height;
687         }
688
689         private void UpdateVisual()
690         {
691             if (null == circularPaginationStyle.IndicatorSize) return;
692             if (null == circularPaginationStyle.IndicatorImageURL) return;
693             if (indicatorCount < 0) return;
694
695             for (int i = 0; i < indicatorList.Count; i++)
696             {
697                 ImageVisual indicator = indicatorList[i];
698                 indicator.Size = new Size2D((int)circularPaginationStyle.IndicatorSize.Width, (int)circularPaginationStyle.IndicatorSize.Height);
699
700                 CheckCenterIndicator(i);
701
702                 if (i == selectedIndex)
703                 {
704                     // If the center image is set before, then should update the center visual separately.
705                     if (isCurrentIndicatorCentered)
706                     {
707                         indicator.URL = circularPaginationStyle.CenterIndicatorImageURL.Selected;
708                     }
709                     else
710                     {
711                         indicator.URL = circularPaginationStyle.IndicatorImageURL.Selected;
712                     }
713                     indicator.Opacity = 1.0f;
714                 }
715                 else
716                 {
717                     // If the center image is set before, then should update the center visual separately.
718                     if (isCurrentIndicatorCentered)
719                     {
720                         indicator.URL = circularPaginationStyle.CenterIndicatorImageURL.Normal;
721                     }
722                     else
723                     {
724                         indicator.URL = circularPaginationStyle.IndicatorImageURL.Normal;
725                     }
726                     indicator.Opacity = 0.5f;
727                 }
728
729                 if (isOddNumber)
730                 {
731                     if (isSymmetrical)
732                     {
733                         indicator.Position = oddArray[middleIndex - (indicatorCount / 2) + i];
734                     }
735                     else
736                     {
737                         indicator.Position = oddArray[(middleIndex - leftIndicatorCount) + i];
738                     }
739
740                 }
741                 else
742                 {
743                     indicator.Position = evenArray[IndicatorCount/2 + i - 1];
744                 }
745             }
746         }
747
748         private void UpdateAsymmetry()
749         {
750             if (null == circularPaginationStyle.IndicatorSize) return;
751             if (null == circularPaginationStyle.IndicatorImageURL) return;
752
753             int listCount = indicatorList.Count;
754
755             for (int i = 0; i < listCount; i++)
756             {
757                 container.RemoveVisual("Indicator" + i);
758             }
759             container.RemoveAll();
760             indicatorList.Clear();
761
762             for (int i = 0; i < listCount; i++)
763             {
764                 ImageVisual newOne = new ImageVisual
765                 {
766                     Size = new Size2D((int)circularPaginationStyle.IndicatorSize.Width, (int)circularPaginationStyle.IndicatorSize.Height),
767                     Position = oddArray[i + (middleIndex - leftIndicatorCount)]
768                 };
769
770                 if (isCenterImageSet && !isSymmetrical && (i == leftIndicatorCount))
771                 {
772                     newOne.URL = circularPaginationStyle.CenterIndicatorImageURL.Normal;
773                 }
774                 else
775                 {
776                     newOne.URL = circularPaginationStyle.IndicatorImageURL.Normal;
777                 }
778                 newOne.Opacity  = 0.5f;
779                 container.AddVisual("Indicator" + i, newOne);
780                 indicatorList.Add(newOne);
781             }
782
783             // If selectedIndex is not set yet, the default value is middle index.
784             if (selectedIndex == -1)
785             {
786                 selectedIndex = leftIndicatorCount;
787             }
788
789             if (isCenterImageSet && (selectedIndex == leftIndicatorCount))
790             {
791                 indicatorList[selectedIndex].URL = circularPaginationStyle.CenterIndicatorImageURL.Selected;
792                 indicatorList[selectedIndex].Opacity = 1.0f;
793             }
794             else
795             {
796                 indicatorList[selectedIndex].URL = circularPaginationStyle.IndicatorImageURL.Selected;
797                 indicatorList[selectedIndex].Opacity = 1.0f;
798             }
799         }
800     }
801 }