2 * Copyright(c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 using System.Collections.Generic;
20 using System.ComponentModel;
21 using System.Diagnostics;
22 using Tizen.NUI.BaseComponents;
23 using Tizen.NUI.Binding;
25 namespace Tizen.NUI.Components
28 /// Pagination shows the number of pages available and the currently active page.
30 /// <since_tizen> 8 </since_tizen>
31 public class Pagination : Control
33 /// <summary>The IndicatorSize bindable property.</summary>
34 [EditorBrowsable(EditorBrowsableState.Never)]
35 public static readonly BindableProperty IndicatorSizeProperty = BindableProperty.Create(nameof(IndicatorSize), typeof(Size), typeof(Pagination), null, propertyChanged: (bindable, oldValue, newValue) =>
39 var pagination = (Pagination)bindable;
40 pagination.indicatorSize = new Size((Size)newValue);
41 pagination.UpdateVisual();
42 pagination.UpdateContainer();
45 defaultValueCreator: (bindable) =>
47 return ((Pagination)bindable).indicatorSize;
50 /// <summary>The IndicatorImageUrlSelector bindable property.</summary>
51 [EditorBrowsable(EditorBrowsableState.Never)]
52 public static readonly BindableProperty IndicatorImageUrlProperty = BindableProperty.Create("IndicatorImageUrl", typeof(Selector<string>), typeof(Pagination), null, propertyChanged: (bindable, oldValue, newValue) =>
54 var pagination = (Pagination)bindable;
55 pagination.indicatorImageUrl = ((Selector<string>)newValue)?.Clone();
56 pagination.UpdateVisual();
58 defaultValueCreator: (bindable) =>
60 return ((Pagination)bindable).indicatorImageUrl;
63 /// <summary>The IndicatorSpacing bindable property.</summary>
64 [EditorBrowsable(EditorBrowsableState.Never)]
65 public static readonly BindableProperty IndicatorSpacingProperty = BindableProperty.Create(nameof(IndicatorSpacing), typeof(int), typeof(Pagination), default(int), propertyChanged: (bindable, oldValue, newValue) =>
67 var pagination = (Pagination)bindable;
68 pagination.indicatorSpacing = (int)newValue;
69 pagination.UpdateVisual();
71 defaultValueCreator: (bindable) =>
73 return ((Pagination)bindable).indicatorSpacing;
76 private VisualView container;
77 private Size indicatorSize = new Size(10, 10);
78 private Selector<string> indicatorImageUrl;
79 private int indicatorSpacing;
80 private List<ImageVisual> indicatorList = new List<ImageVisual>();
82 private int indicatorCount = 0;
83 private int selectedIndex = 0;
85 private Color indicatorColor;
86 private Color selectedIndicatorColor;
87 private Selector<string> lastIndicatorImageUrl;
89 static Pagination() { }
92 /// Creates a new instance of a Pagination.
94 /// <since_tizen> 8 </since_tizen>
95 public Pagination() : base()
100 /// Creates a new instance of a Pagination using style.
102 /// <param name="style">The string to initialize the Pagination</param>
103 /// <since_tizen> 8 </since_tizen>
104 public Pagination(string style) : base(style)
109 /// Creates a new instance of a Pagination using style.
111 /// <param name="paginationStyle">The style object to initialize the Pagination</param>
112 /// <since_tizen> 8 </since_tizen>
113 public Pagination(PaginationStyle paginationStyle) : base(paginationStyle)
118 /// Return currently applied style.
121 /// Modifying contents in style may cause unexpected behaviour.
123 /// <since_tizen> 8 </since_tizen>
124 public PaginationStyle Style => (PaginationStyle)(ViewStyle as PaginationStyle)?.Clone();
127 /// Gets or sets the size of the indicator.
129 /// <since_tizen> 8 </since_tizen>
130 public Size IndicatorSize
132 get => (Size)GetValue(IndicatorSizeProperty);
133 set => SetValue(IndicatorSizeProperty, value);
137 /// Gets or sets the background resource of indicator.
139 /// <since_tizen> 8 </since_tizen>
140 public Selector<string> IndicatorImageUrl
142 get => (Selector<string>)GetValue(IndicatorImageUrlProperty);
143 set => SetValue(IndicatorImageUrlProperty, value);
147 /// This is experimental API.
148 /// Make the last indicator has exceptional image, not common image in the Pagination.
150 [EditorBrowsable(EditorBrowsableState.Never)]
151 public Selector<string> LastIndicatorImageUrl
153 get => lastIndicatorImageUrl;
156 lastIndicatorImageUrl = value;
157 if (value != null && indicatorCount > 0)
159 indicatorList[LastIndicatorIndex].URL = IsLastSelected ? value.Selected : value.Normal;
165 /// Gets or sets the space of the indicator.
167 /// <since_tizen> 8 </since_tizen>
168 public int IndicatorSpacing
170 get => (int)GetValue(IndicatorSpacingProperty);
171 set => SetValue(IndicatorSpacingProperty, value);
176 /// Gets or sets the count of the pages/indicators.
178 /// <since_tizen> 8 </since_tizen>
179 /// <exception cref="ArgumentException">Thrown when the given value is negative.</exception>
180 public int IndicatorCount
184 return indicatorCount;
190 throw new ArgumentException($"Setting {nameof(IndicatorCount)} to negative is not allowed.");
193 if (indicatorCount == value)
198 int prevLastIndex = -1;
200 if (indicatorCount < value)
202 prevLastIndex = LastIndicatorIndex;
203 for (int i = indicatorCount; i < value; i++)
210 for (int i = value; i < indicatorCount; i++)
212 ImageVisual indicator = indicatorList[i];
213 container.RemoveVisual("Indicator" + i);
215 indicatorList.RemoveRange(value, indicatorCount - value);
217 if (selectedIndex >= value)
219 selectedIndex = Math.Max(0, value - 1);
223 SelectIn(indicatorList[selectedIndex]);
227 indicatorCount = value;
229 if (lastIndicatorImageUrl != null && indicatorImageUrl != null && indicatorCount > 0)
231 if (prevLastIndex >= 0)
233 indicatorList[prevLastIndex].URL = prevLastIndex == selectedIndex ? indicatorImageUrl.Selected : indicatorImageUrl.Normal;
235 indicatorList[LastIndicatorIndex].URL = IsLastSelected ? lastIndicatorImageUrl.Selected : lastIndicatorImageUrl.Normal;
242 private void OnIndicatorColorChanged(float r, float g, float b, float a)
244 IndicatorColor = new Color(r, g, b, a);
248 /// Color of the indicator.
250 /// <since_tizen> 8 </since_tizen>
251 public Color IndicatorColor
255 return new Color(OnIndicatorColorChanged, indicatorColor);
264 if (indicatorColor == null)
266 indicatorColor = new Color((Color)value);
270 if (indicatorColor == value)
275 indicatorColor = value;
278 if (indicatorCount == 0)
283 for (int i = 0; i < indicatorCount; i++)
285 if (i == selectedIndex)
290 ImageVisual indicator = indicatorList[i];
291 indicator.MixColor = indicatorColor;
292 indicator.Opacity = indicatorColor.A;
297 private void OnSelectedIndicatorColorChanged(float r, float g, float b, float a)
299 SelectedIndicatorColor = new Color(r, g, b, a);
303 /// Color of the selected indicator.
305 /// <since_tizen> 8 </since_tizen>
306 public Color SelectedIndicatorColor
310 return new Color(OnSelectedIndicatorColorChanged, selectedIndicatorColor);
319 if (selectedIndicatorColor == null)
321 selectedIndicatorColor = new Color((Color)value);
325 if (selectedIndicatorColor == value)
330 selectedIndicatorColor = value;
333 if (indicatorList.Count > selectedIndex)
335 var indicator = indicatorList[selectedIndex];
336 indicator.MixColor = selectedIndicatorColor;
337 indicator.Opacity = selectedIndicatorColor.A;
343 /// Gets or sets the index of the select indicator.
345 /// <since_tizen> 8 </since_tizen>
346 public int SelectedIndex
350 return selectedIndex;
354 var refinedValue = Math.Max(0, Math.Min(value, indicatorCount - 1));
356 if (selectedIndex == refinedValue)
361 Debug.Assert(refinedValue >= 0 && refinedValue < indicatorCount);
362 Debug.Assert(selectedIndex >= 0 && selectedIndex < indicatorCount);
364 SelectOut(indicatorList[selectedIndex]);
366 selectedIndex = refinedValue;
368 SelectIn(indicatorList[selectedIndex]);
370 if (Accessibility.Accessibility.Enabled && IsHighlighted)
372 EmitAccessibilityEvent(AccessibilityPropertyChangeEvent.Value);
378 /// Retrieves the position of a indicator by index.
380 /// <param name="index">Indicator index</param>
381 /// <returns>The position of a indicator by index.</returns>
382 /// <since_tizen> 8 </since_tizen>
383 public Position GetIndicatorPosition(int index)
385 if (index < 0 || index >= indicatorList.Count)
389 return new Position(indicatorList[index].Position.X + container.PositionX, indicatorList[index].Position.Y + container.PositionY);
395 [EditorBrowsable(EditorBrowsableState.Never)]
396 protected override double AccessibilityGetMinimum()
404 [EditorBrowsable(EditorBrowsableState.Never)]
405 protected override double AccessibilityGetCurrent()
407 return (double)SelectedIndex;
413 [EditorBrowsable(EditorBrowsableState.Never)]
414 protected override double AccessibilityGetMaximum()
416 return (double)IndicatorCount;
422 [EditorBrowsable(EditorBrowsableState.Never)]
423 protected override bool AccessibilitySetCurrent(double value)
425 int integerValue = (int)value;
427 if (integerValue >= 0 && integerValue <= IndicatorCount)
429 SelectedIndex = integerValue;
437 /// Minimum increment.
439 [EditorBrowsable(EditorBrowsableState.Never)]
440 protected override double AccessibilityGetMinimumIncrement()
446 [EditorBrowsable(EditorBrowsableState.Never)]
447 public override void OnInitialize()
450 SetAccessibilityConstructor(Role.ScrollBar, AccessibilityInterface.Value);
451 AccessibilityHighlightable = true;
452 AppendAccessibilityAttribute("style", "pagecontrolbyvalue");
454 container = new VisualView()
457 ParentOrigin = Tizen.NUI.ParentOrigin.CenterLeft,
458 PivotPoint = Tizen.NUI.PivotPoint.CenterLeft,
459 PositionUsesPivotPoint = true,
463 //TODO: Apply color properties from PaginationStyle class.
464 indicatorColor = new Color(1.0f, 1.0f, 1.0f, 0.5f);
465 selectedIndicatorColor = new Color(1.0f, 1.0f, 1.0f, 1.0f);
469 /// You can override it to do your select out operation.
471 /// <param name="selectOutIndicator">The indicator will be selected out</param>
472 /// <since_tizen> 8 </since_tizen>
473 protected virtual void SelectOut(VisualMap selectOutIndicator)
475 if (!(selectOutIndicator is ImageVisual visual)) return;
476 visual.URL = ((IsLastSelected && lastIndicatorImageUrl != null) ? lastIndicatorImageUrl : indicatorImageUrl)?.Normal;
478 if (indicatorColor == null)
480 //TODO: Apply color properties from PaginationStyle class.
481 visual.MixColor = new Color(1.0f, 1.0f, 1.0f, 0.5f);
482 visual.Opacity = 0.5f;
486 visual.MixColor = indicatorColor;
487 visual.Opacity = indicatorColor.A;
492 /// You can override it to do your select in operation.
494 /// <param name="selectInIndicator">The indicator will be selected in</param>
495 /// <since_tizen> 8 </since_tizen>
496 protected virtual void SelectIn(VisualMap selectInIndicator)
498 if (!(selectInIndicator is ImageVisual visual)) return;
499 visual.URL = ((IsLastSelected && lastIndicatorImageUrl != null) ? lastIndicatorImageUrl : indicatorImageUrl)?.Selected;
501 if (selectedIndicatorColor == null)
503 //TODO: Apply color properties from PaginationStyle class.
504 visual.MixColor = new Color(1.0f, 1.0f, 1.0f, 1.0f);
505 visual.Opacity = 1.0f;
509 visual.MixColor = selectedIndicatorColor;
510 visual.Opacity = selectedIndicatorColor.A;
515 /// you can override it to create your own default style.
517 /// <returns>The default pagination style.</returns>
518 /// <since_tizen> 8 </since_tizen>
519 protected override ViewStyle CreateViewStyle()
521 return new PaginationStyle();
525 /// you can override it to clean-up your own resources.
527 /// <param name="type">DisposeTypes</param>
528 /// <since_tizen> 8 </since_tizen>
529 protected override void Dispose(DisposeTypes type)
536 if (type == DisposeTypes.Explicit)
538 container.RemoveAll();
539 indicatorList.Clear();
541 this.Remove(container);
549 private void CreateIndicator(int index)
551 Debug.Assert(indicatorSize != null);
553 ImageVisual indicator = new ImageVisual
555 URL = indicatorImageUrl?.Normal,
556 Size = indicatorSize,
557 //TODO: Apply color properties from PaginationStyle class.
558 MixColor = (indicatorColor == null) ? new Color(1.0f, 1.0f, 1.0f, 0.5f) : indicatorColor,
559 Opacity = (indicatorColor == null) ? 0.5f : indicatorColor.A
561 indicator.Position = new Vector2((int)(indicatorSize.Width + indicatorSpacing) * indicatorList.Count, 0);
562 container.AddVisual("Indicator" + indicatorList.Count, indicator);
563 indicatorList.Add(indicator);
565 if (index == selectedIndex)
567 SelectIn(indicatorList[selectedIndex]);
571 private void UpdateContainer()
573 Debug.Assert(indicatorSize != null);
575 if (indicatorList.Count > 0)
577 container.SizeWidth = (indicatorSize.Width + indicatorSpacing) * indicatorList.Count - indicatorSpacing;
581 container.SizeWidth = 0;
583 container.SizeHeight = indicatorSize.Height;
584 container.PositionX = (int)((this.SizeWidth - container.SizeWidth) / 2);
587 private void UpdateVisual()
589 Debug.Assert(indicatorSize != null);
591 if (indicatorImageUrl == null)
596 for (int i = 0; i < indicatorList.Count; i++)
598 ImageVisual indicator = indicatorList[i];
599 indicator.URL = indicatorImageUrl?.Normal;
600 indicator.Size = indicatorSize;
601 indicator.Position = new Vector2((int)(indicatorSize.Width + indicatorSpacing) * i, 0);
604 if (lastIndicatorImageUrl != null && indicatorCount > 0)
606 indicatorList[LastIndicatorIndex].URL = lastIndicatorImageUrl.Normal;
610 private int LastIndicatorIndex => IndicatorCount - 1;
611 private bool IsLastSelected => LastIndicatorIndex == selectedIndex;