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.ComponentModel;
20 using System.Globalization;
21 using Tizen.NUI.BaseComponents;
22 using Tizen.NUI.Binding;
24 // A spin control (for continuously changing values when users can easily predict a set of values)
28 ///Spins the CustomView class.
30 /// <since_tizen> 3 </since_tizen>
31 public class Spin : CustomView
36 [EditorBrowsable(EditorBrowsableState.Never)]
37 public static readonly BindableProperty ValueProperty = BindableProperty.Create(nameof(Value), typeof(int), typeof(Tizen.NUI.Spin), 0, propertyChanged: (bindable, oldValue, newValue) =>
39 var instance = (Tizen.NUI.Spin)bindable;
42 instance.InternalValue = (int)newValue;
45 defaultValueCreator: (bindable) =>
47 var instance = (Tizen.NUI.Spin)bindable;
48 return instance.InternalValue;
54 [EditorBrowsable(EditorBrowsableState.Never)]
55 public static readonly BindableProperty MinValueProperty = BindableProperty.Create(nameof(MinValue), typeof(int), typeof(Tizen.NUI.Spin), 0, propertyChanged: (bindable, oldValue, newValue) =>
57 var instance = (Tizen.NUI.Spin)bindable;
60 instance.InternalMinValue = (int)newValue;
63 defaultValueCreator: (bindable) =>
65 var instance = (Tizen.NUI.Spin)bindable;
66 return instance.InternalMinValue;
72 [EditorBrowsable(EditorBrowsableState.Never)]
73 public static readonly BindableProperty MaxValueProperty = BindableProperty.Create(nameof(MaxValue), typeof(int), typeof(Tizen.NUI.Spin), 0, propertyChanged: (bindable, oldValue, newValue) =>
75 var instance = (Tizen.NUI.Spin)bindable;
78 instance.InternalMaxValue = (int)newValue;
81 defaultValueCreator: (bindable) =>
83 var instance = (Tizen.NUI.Spin)bindable;
84 return instance.InternalMaxValue;
90 [EditorBrowsable(EditorBrowsableState.Never)]
91 public static readonly BindableProperty StepProperty = BindableProperty.Create(nameof(Step), typeof(int), typeof(Tizen.NUI.Spin), 0, propertyChanged: (bindable, oldValue, newValue) =>
93 var instance = (Tizen.NUI.Spin)bindable;
96 instance.InternalStep = (int)newValue;
99 defaultValueCreator: (bindable) =>
101 var instance = (Tizen.NUI.Spin)bindable;
102 return instance.InternalStep;
106 /// WrappingEnabledProperty
108 [EditorBrowsable(EditorBrowsableState.Never)]
109 public static readonly BindableProperty WrappingEnabledProperty = BindableProperty.Create(nameof(WrappingEnabled), typeof(bool), typeof(Tizen.NUI.Spin), false, propertyChanged: (bindable, oldValue, newValue) =>
111 var instance = (Tizen.NUI.Spin)bindable;
112 if (newValue != null)
114 instance.InternalWrappingEnabled = (bool)newValue;
117 defaultValueCreator: (bindable) =>
119 var instance = (Tizen.NUI.Spin)bindable;
120 return instance.InternalWrappingEnabled;
124 /// TextPointSizeProperty
126 [EditorBrowsable(EditorBrowsableState.Never)]
127 public static readonly BindableProperty TextPointSizeProperty = BindableProperty.Create(nameof(TextPointSize), typeof(int), typeof(Tizen.NUI.Spin), 0, propertyChanged: (bindable, oldValue, newValue) =>
129 var instance = (Tizen.NUI.Spin)bindable;
130 if (newValue != null)
132 instance.InternalTextPointSize = (int)newValue;
135 defaultValueCreator: (bindable) =>
137 var instance = (Tizen.NUI.Spin)bindable;
138 return instance.InternalTextPointSize;
142 /// TextColorProperty
144 [EditorBrowsable(EditorBrowsableState.Never)]
145 public static readonly BindableProperty TextColorProperty = BindableProperty.Create(nameof(TextColor), typeof(Tizen.NUI.Color), typeof(Tizen.NUI.Spin), null, propertyChanged: (bindable, oldValue, newValue) =>
147 var instance = (Tizen.NUI.Spin)bindable;
148 if (newValue != null)
150 instance.InternalTextColor = (Tizen.NUI.Color)newValue;
153 defaultValueCreator: (bindable) =>
155 var instance = (Tizen.NUI.Spin)bindable;
156 return instance.InternalTextColor;
160 /// MaxTextLengthProperty
162 [EditorBrowsable(EditorBrowsableState.Never)]
163 public static readonly BindableProperty MaxTextLengthProperty = BindableProperty.Create(nameof(MaxTextLength), typeof(int), typeof(Tizen.NUI.Spin), 0, propertyChanged: (bindable, oldValue, newValue) =>
165 var instance = (Tizen.NUI.Spin)bindable;
166 if (newValue != null)
168 instance.InternalMaxTextLength = (int)newValue;
171 defaultValueCreator: (bindable) =>
173 var instance = (Tizen.NUI.Spin)bindable;
174 return instance.InternalMaxTextLength;
180 [EditorBrowsable(EditorBrowsableState.Never)]
181 public static readonly BindableProperty SpinTextProperty = BindableProperty.Create(nameof(SpinText), typeof(Tizen.NUI.BaseComponents.TextField), typeof(Tizen.NUI.Spin), null, propertyChanged: (bindable, oldValue, newValue) =>
183 var instance = (Tizen.NUI.Spin)bindable;
184 if (newValue != null)
186 instance.InternalSpinText = (Tizen.NUI.BaseComponents.TextField)newValue;
189 defaultValueCreator: (bindable) =>
191 var instance = (Tizen.NUI.Spin)bindable;
192 return instance.InternalSpinText;
196 /// IndicatorImageProperty
198 [EditorBrowsable(EditorBrowsableState.Never)]
199 public static readonly BindableProperty IndicatorImageProperty = BindableProperty.Create(nameof(IndicatorImage), typeof(string), typeof(Tizen.NUI.Spin), string.Empty, propertyChanged: (bindable, oldValue, newValue) =>
201 var instance = (Tizen.NUI.Spin)bindable;
202 if (newValue != null)
204 instance.InternalIndicatorImage = (string)newValue;
207 defaultValueCreator: (bindable) =>
209 var instance = (Tizen.NUI.Spin)bindable;
210 return instance.InternalIndicatorImage;
213 private VisualBase arrowVisual;
214 private TextField textField;
215 private int arrowVisualPropertyIndex;
216 private string arrowImage;
217 private int currentValue;
218 private int minValue;
219 private int maxValue;
220 private int singleStep;
221 private bool wrappingEnabled;
222 private int pointSize;
223 private Color textColor;
224 private Color textBackgroundColor;
225 private int maxTextLength;
227 // static constructor registers the control type (only runs once)
230 // ViewRegistry registers control type with DALi type registry
231 // also uses introspection to find any properties that need to be registered with type registry
232 CustomViewRegistry.Instance.Register(CreateInstance, typeof(Spin));
236 /// Creates an initialized spin.
238 /// <since_tizen> 3 </since_tizen>
239 public Spin() : base(typeof(Spin).FullName, CustomViewBehaviour.RequiresKeyboardNavigationSupport)
244 /// Value to be set in the spin.
246 /// <since_tizen> 3 </since_tizen>
247 [ScriptableProperty()]
248 // GetValue() is in BindableObject. It's different from this Value.
249 [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1721: Property names should not match get methods")]
254 return (int)GetValue(ValueProperty);
258 SetValue(ValueProperty, value);
259 NotifyPropertyChanged();
263 private int InternalValue
271 NUILog.Debug("Value set to " + value);
272 currentValue = value;
274 // Make sure no invalid value is accepted
275 if (currentValue < minValue)
277 currentValue = minValue;
280 if (currentValue > maxValue)
282 currentValue = maxValue;
285 textField.Text = currentValue.ToString();
290 /// Minimum value of the spin value.
292 /// <since_tizen> 3 </since_tizen>
293 [ScriptableProperty()]
298 return (int)GetValue(MinValueProperty);
302 SetValue(MinValueProperty, value);
303 NotifyPropertyChanged();
307 private int InternalMinValue
320 /// Maximum value of the spin value.
322 /// <since_tizen> 3 </since_tizen>
323 [ScriptableProperty()]
328 return (int)GetValue(MaxValueProperty);
332 SetValue(MaxValueProperty, value);
333 NotifyPropertyChanged();
337 private int InternalMaxValue
350 /// Increasing, decreasing step of the spin value when up or down keys are pressed.
352 /// <since_tizen> 3 </since_tizen>
353 [ScriptableProperty()]
358 return (int)GetValue(StepProperty);
362 SetValue(StepProperty, value);
363 NotifyPropertyChanged();
367 private int InternalStep
380 /// Wrapping enabled status.
382 /// <since_tizen> 3 </since_tizen>
383 [ScriptableProperty()]
384 public bool WrappingEnabled
388 return (bool)GetValue(WrappingEnabledProperty);
392 SetValue(WrappingEnabledProperty, value);
393 NotifyPropertyChanged();
397 private bool InternalWrappingEnabled
401 return wrappingEnabled;
405 wrappingEnabled = value;
410 /// Text point size of the spin value.
412 /// <since_tizen> 3 </since_tizen>
413 [ScriptableProperty()]
414 public int TextPointSize
418 return (int)GetValue(TextPointSizeProperty);
422 SetValue(TextPointSizeProperty, value);
423 NotifyPropertyChanged();
427 private int InternalTextPointSize
436 textField.PointSize = pointSize;
441 /// The color of the spin value.
443 /// <since_tizen> 3 </since_tizen>
444 [ScriptableProperty()]
445 public Color TextColor
449 return GetValue(TextColorProperty) as Color;
453 SetValue(TextColorProperty, value);
454 NotifyPropertyChanged();
458 private Color InternalTextColor
468 NUILog.Debug("TextColor set to " + value.R + "," + value.G + "," + value.B);
472 textField.TextColor = textColor;
477 /// Maximum text length of the spin value.
479 /// <since_tizen> 3 </since_tizen>
480 [ScriptableProperty()]
481 public int MaxTextLength
485 return (int)GetValue(MaxTextLengthProperty);
489 SetValue(MaxTextLengthProperty, value);
490 NotifyPropertyChanged();
494 private int InternalMaxTextLength
498 return maxTextLength;
502 maxTextLength = value;
503 textField.MaxLength = maxTextLength;
508 /// Reference of TextField of the spin.
510 /// <since_tizen> 3 </since_tizen>
511 public TextField SpinText
515 return GetValue(SpinTextProperty) as TextField;
519 SetValue(SpinTextProperty, value);
520 NotifyPropertyChanged();
524 private TextField InternalSpinText
537 /// Show indicator image, for example, up or down arrow image.
539 /// <since_tizen> 3 </since_tizen>
540 public string IndicatorImage
544 return GetValue(IndicatorImageProperty) as string;
548 SetValue(IndicatorImageProperty, value);
549 NotifyPropertyChanged();
553 private string InternalIndicatorImage
562 var ptMap = new PropertyMap();
563 var temp = new PropertyValue((int)Visual.Type.Image);
564 ptMap.Add(Visual.Property.Type, temp);
567 temp = new PropertyValue(arrowImage);
568 ptMap.Add(ImageVisualProperty.URL, temp);
571 temp = new PropertyValue(150);
572 ptMap.Add(ImageVisualProperty.DesiredHeight, temp);
575 temp = new PropertyValue(150);
576 ptMap.Add(ImageVisualProperty.DesiredWidth, temp);
579 arrowVisual = VisualFactory.Instance.CreateVisual(ptMap);
582 RegisterVisual(arrowVisualPropertyIndex, arrowVisual);
586 // Called by DALi Builder if it finds a Spin control in a JSON file
587 static CustomView CreateInstance()
593 /// Overrides the method of OnInitialize() for the CustomView class.<br />
594 /// This method is called after the control has been initialized.<br />
595 /// Derived classes should do any second phase initialization by overriding this method.<br />
597 /// <since_tizen> 3 </since_tizen>
598 public override void OnInitialize()
600 // Initialize the propertiesControl
601 arrowImage = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "picture.png";
602 textBackgroundColor = new Color(0.6f, 0.6f, 0.6f, 1.0f);
609 // Create image visual for the arrow keys
610 var temp = new PropertyValue(arrowImage);
611 arrowVisualPropertyIndex = RegisterProperty("ArrowImage", temp, Tizen.NUI.PropertyAccessMode.ReadWrite);
614 var ptMap = new PropertyMap();
615 temp = new PropertyValue((int)Visual.Type.Image);
616 ptMap.Add(Visual.Property.Type, temp);
619 temp = new PropertyValue(arrowImage);
620 ptMap.Add(ImageVisualProperty.URL, temp);
623 temp = new PropertyValue(150);
624 ptMap.Add(ImageVisualProperty.DesiredHeight, temp);
627 temp = new PropertyValue(150);
628 ptMap.Add(ImageVisualProperty.DesiredWidth, temp);
631 arrowVisual = VisualFactory.Instance.CreateVisual(ptMap);
633 RegisterVisual(arrowVisualPropertyIndex, arrowVisual);
635 // Create a text field
636 textField = new TextField();
637 textField.PivotPoint = Tizen.NUI.PivotPoint.Center;
638 textField.WidthResizePolicy = ResizePolicyType.SizeRelativeToParent;
639 textField.HeightResizePolicy = ResizePolicyType.SizeRelativeToParent;
640 textField.SizeModeFactor = new Vector3(1.0f, 0.45f, 1.0f);
641 textField.PlaceholderText = "----";
642 textField.BackgroundColor = textBackgroundColor;
643 textField.HorizontalAlignment = HorizontalAlignment.Center;
644 textField.VerticalAlignment = VerticalAlignment.Center;
645 textField.Focusable = (true);
646 textField.Name = "_textField";
647 textField.Position2D = new Position2D(0, 40);
651 textField.FocusGained += TextFieldKeyInputFocusGained;
652 textField.FocusLost += TextFieldKeyInputFocusLost;
656 /// Overrides the method of GetNaturalSize() for the CustomView class.<br />
657 /// Returns the natural size of the actor.<br />
659 /// <returns> Natural size of this spin itself.</returns>
660 /// <since_tizen> 3 </since_tizen>
661 public override Size2D GetNaturalSize()
663 return new Size2D(150, 150);
667 /// An event handler is used when the TextField in the spin gets the key focus.<br />
668 /// Make sure when the current spin that takes input focus, also takes the keyboard focus.<br />
669 /// For example, when you tap the spin directly.<br />
671 /// <param name="source">Sender of this event.</param>
672 /// <param name="e">Event arguments.</param>
673 /// <since_tizen> 3 </since_tizen>
674 public void TextFieldKeyInputFocusGained(object source, EventArgs e)
676 FocusManager.Instance.SetCurrentFocusView(textField);
680 /// An event handler when the TextField in the spin looses it's key focus.
682 /// <param name="source"></param>
683 /// <param name="e"></param>
684 /// <since_tizen> 3 </since_tizen>
685 public void TextFieldKeyInputFocusLost(object source, EventArgs e)
687 int previousValue = currentValue;
689 // If the input value is invalid, change it back to the previous valid value
690 if (int.TryParse(textField.Text, NumberStyles.None, CultureInfo.InvariantCulture, out currentValue))
692 if (currentValue < minValue || currentValue > maxValue)
694 currentValue = previousValue;
699 currentValue = previousValue;
702 // Otherwise take the new value
703 this.Value = currentValue;
707 /// Overrides the method of GetNextKeyboardFocusableView() for the CustomView class.<br />
708 /// Gets the next key focusable view in this view towards the given direction.<br />
709 /// A view needs to override this function in order to support two-dimensional key navigation.<br />
711 /// <param name="currentFocusedView">The current focused view.</param>
712 /// <param name="direction">The direction to move the focus towards.</param>
713 /// <param name="loopEnabled">Whether the focus movement should be looped within the control.</param>
714 /// <returns>The next keyboard focusable view in this control or an empty handle if no view can be focused.</returns>
715 /// <since_tizen> 3 </since_tizen>
716 public override View GetNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled)
718 // Respond to Up/Down keys to change the value while keeping the current spin focused
719 View nextFocusedView = currentFocusedView;
720 if (direction == View.FocusDirection.Up)
722 this.Value += this.Step;
723 nextFocusedView = textField;
725 else if (direction == View.FocusDirection.Down)
727 this.Value -= this.Step;
728 nextFocusedView = textField;
736 return nextFocusedView;