Follow formatting NUI
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / DropDown.cs
1 /*
2  * Copyright(c) 2019 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 Tizen.NUI.BaseComponents;
20 using System.ComponentModel;
21 using Tizen.NUI.Binding;
22 using Tizen.NUI.Accessibility;
23
24 namespace Tizen.NUI.Components
25 {
26     /// <summary>
27     /// DropDown is one kind of common component, a dropdown allows the user click dropdown button to choose one value from a list.
28     /// </summary>
29     /// <since_tizen> 6 </since_tizen>
30     /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
31     [EditorBrowsable(EditorBrowsableState.Never)]
32     public partial class DropDown : Control
33     {
34         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
35         [EditorBrowsable(EditorBrowsableState.Never)]
36         public static readonly BindableProperty ListPaddingProperty = BindableProperty.Create(nameof(ListPadding), typeof(Extents), typeof(DropDown), null, propertyChanged: (bindable, oldValue, newValue) =>
37         {
38             var instance = (DropDown)bindable;
39             if (newValue != null)
40             {
41                 instance.dropDownStyle.ListPadding.CopyFrom((Extents)newValue);
42                 instance.UpdateDropDown();
43             }
44         },
45         defaultValueCreator: (bindable) =>
46         {
47             var instance = (DropDown)bindable;
48             return instance.dropDownStyle.ListPadding;
49         });
50         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
51         [EditorBrowsable(EditorBrowsableState.Never)]
52         public static readonly BindableProperty SelectedItemIndexProperty = BindableProperty.Create(nameof(SelectedItemIndex), typeof(int), typeof(DropDown), 0, propertyChanged: (bindable, oldValue, newValue) =>
53         {
54             var instance = (DropDown)bindable;
55             if (newValue != null)
56             {
57                 int selectedItemIndex = (int)newValue;
58                 if (selectedItemIndex == instance.dropDownStyle.SelectedItemIndex || instance.adapter == null || selectedItemIndex < 0 || selectedItemIndex >= instance.adapter.GetItemCount())
59                 {
60                     return;
61                 }
62                 instance.SetListItemToSelected((uint)selectedItemIndex);
63             }
64         },
65         defaultValueCreator: (bindable) =>
66         {
67             var instance = (DropDown)bindable;
68             return instance.dropDownStyle.SelectedItemIndex;
69         });
70         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
71         [EditorBrowsable(EditorBrowsableState.Never)]
72         public static readonly BindableProperty ListMarginProperty = BindableProperty.Create(nameof(ListMargin), typeof(Extents), typeof(DropDown), null, propertyChanged: (bindable, oldValue, newValue) =>
73         {
74             var instance = (DropDown)bindable;
75             if (newValue != null)
76             {
77                 instance.dropDownStyle.ListMargin.CopyFrom((Extents)newValue);
78                 instance.UpdateDropDown();
79             }
80         },
81         defaultValueCreator: (bindable) =>
82         {
83             var instance = (DropDown)bindable;
84             return instance.dropDownStyle.ListMargin;
85         });
86         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
87         [EditorBrowsable(EditorBrowsableState.Never)]
88         public static readonly BindableProperty ListRelativeOrientationProperty = BindableProperty.Create(nameof(ListRelativeOrientation), typeof(ListOrientation), typeof(DropDown), ListOrientation.Left, propertyChanged: (bindable, oldValue, newValue) =>
89         {
90             var instance = (DropDown)bindable;
91             if (newValue != null)
92             {
93                 instance.dropDownStyle.ListRelativeOrientation = (ListOrientation)newValue;
94                 instance.UpdateDropDown();
95             }
96         },
97         defaultValueCreator: (bindable) =>
98         {
99             var instance = (DropDown)bindable;
100             return instance.dropDownStyle.ListRelativeOrientation;
101         });
102         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
103         [EditorBrowsable(EditorBrowsableState.Never)]
104         public static readonly BindableProperty SpaceBetweenButtonTextAndIconProperty = BindableProperty.Create(nameof(SpaceBetweenButtonTextAndIcon), typeof(int), typeof(DropDown), 0, propertyChanged: (bindable, oldValue, newValue) =>
105         {
106             var instance = (DropDown)bindable;
107             if (newValue != null)
108             {
109                 instance.dropDownStyle.SpaceBetweenButtonTextAndIcon = (int)newValue;
110             }
111         },
112         defaultValueCreator: (bindable) =>
113         {
114             var instance = (DropDown)bindable;
115             return instance.dropDownStyle.SpaceBetweenButtonTextAndIcon;
116         });
117
118         #region DropDown
119         private Button button = null;
120         private TextLabel headerText = null;
121         private TextLabel buttonText = null;
122         private ImageView listBackgroundImage = null;
123         // Component that scrolls the child added to it.
124         private ScrollableBase scrollableBase = null;
125
126         // The LinearLayout container to house the items in the drop down list.
127         private View dropDownMenuFullList = null;
128         private DropDownListBridge adapter = new DropDownListBridge();
129         private DropDownItemView selectedItemView = null;
130         private TapGestureDetector tapGestureDetector = null;
131
132         private bool itemPressed = false;
133
134         static DropDown() { }
135
136         /// <summary>
137         /// Creates a new instance of a DropDown.
138         /// </summary>
139         /// <since_tizen> 6 </since_tizen>
140         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
141         [EditorBrowsable(EditorBrowsableState.Never)]
142         public DropDown() : base()
143         {
144             AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Trait, "DropDown");
145         }
146
147         /// <summary>
148         /// Creates a new instance of a DropDown with style.
149         /// </summary>
150         /// <param name="style">Create DropDown by special style defined in UX.</param>
151         /// <since_tizen> 6 </since_tizen>
152         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
153         [EditorBrowsable(EditorBrowsableState.Never)]
154         public DropDown(string style) : base(style)
155         {
156             AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Trait, "DropDown");
157         }
158
159         /// <summary>
160         /// Creates a new instance of a DropDown with style.
161         /// </summary>
162         /// <param name="dropDownStyle">Create DropDown by style customized by user.</param>
163         /// <since_tizen> 6 </since_tizen>
164         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
165         [EditorBrowsable(EditorBrowsableState.Never)]
166         public DropDown(DropDownStyle dropDownStyle) : base(dropDownStyle)
167         {
168             AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Trait, "DropDown");
169         }
170
171         /// <summary>
172         /// An event for the item clicked signal which can be used to subscribe or unsubscribe the event handler provided by the user.<br />
173         /// </summary>
174         /// <since_tizen> 6 </since_tizen>
175         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
176         [EditorBrowsable(EditorBrowsableState.Never)]
177         public event EventHandler<ItemClickEventArgs> ItemClickEvent;
178
179         /// <summary>
180         /// List position in relation to the main button.
181         /// </summary>
182         /// <since_tizen> 6 </since_tizen>
183         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
184         [EditorBrowsable(EditorBrowsableState.Never)]
185         public enum ListOrientation
186         {
187             /// <summary>
188             /// Left.
189             /// </summary>
190             /// <since_tizen> 6 </since_tizen>
191             /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
192             [EditorBrowsable(EditorBrowsableState.Never)]
193             Left,
194             /// <summary>
195             /// Right.
196             /// </summary>
197             /// <since_tizen> 6 </since_tizen>
198             /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
199             [EditorBrowsable(EditorBrowsableState.Never)]
200             Right,
201         }
202
203         /// <summary>
204         /// Get or set header text.
205         /// </summary>
206         /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
207         [EditorBrowsable(EditorBrowsableState.Never)]
208         public TextLabel HeaderText
209         {
210             get
211             {
212                 if (null == headerText)
213                 {
214                     headerText = new TextLabel()
215                     {
216                         WidthResizePolicy = ResizePolicyType.UseNaturalSize,
217                         HeightResizePolicy = ResizePolicyType.UseNaturalSize,
218                         HorizontalAlignment = HorizontalAlignment.Center,
219                         VerticalAlignment = VerticalAlignment.Center,
220                         ParentOrigin = NUI.ParentOrigin.Center,
221                         PivotPoint = NUI.ParentOrigin.Center,
222                         PositionUsesPivotPoint = true,
223                         Name = "DropDownHeaderText"
224                     };
225                     Add(headerText);
226                 }
227                 return headerText;
228             }
229             internal set
230             {
231                 headerText = value;
232             }
233         }
234
235         /// <summary>
236         /// Get or set button.
237         /// </summary>
238         /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
239         [EditorBrowsable(EditorBrowsableState.Never)]
240         public Button Button
241         {
242             get
243             {
244                 if (null == button)
245                 {
246                     button = new Button()
247                     {
248                         ParentOrigin = NUI.ParentOrigin.TopLeft,
249                         PivotPoint = NUI.PivotPoint.TopLeft,
250                         PositionUsesPivotPoint = true,
251                         HeightResizePolicy = ResizePolicyType.FitToChildren,
252                         IconRelativeOrientation = Button.IconOrientation.Right,
253                         Name = "DropDownButton"
254                     };
255                     button.ClickEvent += ButtonClickEvent;
256                     Add(button);
257
258                     if (null == buttonText)
259                     {
260                         buttonText = new TextLabel();
261                     }
262                 }
263                 return button;
264             }
265             internal set
266             {
267                 button = value;
268             }
269         }
270
271         /// <summary>
272         /// Get or set the background image of list.
273         /// </summary>
274         /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
275         [EditorBrowsable(EditorBrowsableState.Never)]
276         public ImageView ListBackgroundImage
277         {
278             get
279             {
280                 if (null == listBackgroundImage)
281                 {
282                     listBackgroundImage = new ImageView()
283                     {
284                         Name = "ListBackgroundImage",
285                         PositionUsesPivotPoint = true,
286                         ParentOrigin = Tizen.NUI.ParentOrigin.TopLeft,
287                         PivotPoint = Tizen.NUI.PivotPoint.TopLeft,
288                         WidthResizePolicy = ResizePolicyType.FitToChildren,
289                         HeightResizePolicy = ResizePolicyType.FitToChildren,
290                     };
291                     Add(listBackgroundImage);
292
293                     if (null == scrollableBase) // scrollableBase used to test of ListContainer Setup invoked already
294                     {
295                         SetUpListContainer();
296                     }
297                 }
298                 return listBackgroundImage;
299             }
300             internal set
301             {
302                 listBackgroundImage = value;
303             }
304         }
305
306         /// <summary>
307         /// Return a copied Style instance of DropDown
308         /// </summary>
309         /// <remarks>
310         /// It returns copied Style instance and changing it does not effect to the DropDown.
311         /// Style setting is possible by using constructor or the function of ApplyStyle(ViewStyle viewStyle)
312         /// </remarks>
313         /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
314         [EditorBrowsable(EditorBrowsableState.Never)]
315         public new DropDownStyle Style
316         {
317             get
318             {
319                 var result = new DropDownStyle(dropDownStyle);
320                 result.CopyPropertiesFromView(this);
321                 result.Button.CopyPropertiesFromView(Button);
322                 result.HeaderText.CopyPropertiesFromView(HeaderText);
323                 result.ListBackgroundImage.CopyPropertiesFromView(ListBackgroundImage);
324                 return result;
325             }
326         }
327
328         /// <summary>
329         /// Space between button text and button icon in DropDown.
330         /// </summary>
331         /// <since_tizen> 6 </since_tizen>
332         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
333         public int SpaceBetweenButtonTextAndIcon
334         {
335             get => (int)GetValue(SpaceBetweenButtonTextAndIconProperty);
336             set => SetValue(SpaceBetweenButtonTextAndIconProperty, value);
337         }
338
339         /// <summary>
340         /// List relative orientation in DropDown.
341         /// </summary>
342         /// <since_tizen> 6 </since_tizen>
343         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
344         public ListOrientation ListRelativeOrientation
345         {
346             get => (ListOrientation)GetValue(ListRelativeOrientationProperty);
347             set => SetValue(ListRelativeOrientationProperty, value);
348         }
349
350         /// <summary>
351         /// Space in list.
352         /// </summary>
353         /// <since_tizen> 6 </since_tizen>
354         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
355         public Extents ListMargin
356         {
357             get
358             {
359                 Extents tmp = (Extents)GetValue(ListMarginProperty);
360                 return new Extents((ushort start, ushort end, ushort top, ushort bottom) => { ListMargin = new Extents(start, end, top, bottom); }, tmp.Start, tmp.End, tmp.Top, tmp.Bottom);
361             }
362             set => SetValue(ListMarginProperty, value);
363         }
364
365         /// <summary>
366         /// Selected item index in list.
367         /// </summary>
368         /// <since_tizen> 6 </since_tizen>
369         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
370         public int SelectedItemIndex
371         {
372             get => (int)GetValue(SelectedItemIndexProperty);
373             set => SetValue(SelectedItemIndexProperty, value);
374         }
375
376         /// <summary>
377         /// List padding in DropDown.
378         /// </summary>
379         /// <since_tizen> 6 </since_tizen>
380         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
381         public Extents ListPadding
382         {
383             get
384             {
385                 Extents tmp = (Extents)GetValue(ListPaddingProperty);
386                 return new Extents((ushort start, ushort end, ushort top, ushort bottom) => { ListPadding = new Extents(start, end, top, bottom); }, tmp.Start, tmp.End, tmp.Top, tmp.Bottom);
387             }
388             set => SetValue(ListPaddingProperty, value);
389         }
390
391         private DropDownStyle dropDownStyle => ViewStyle as DropDownStyle;
392
393         /// <summary>
394         /// Add list item by item data. The added item will be added to end of all items automatically.
395         /// </summary>
396         /// <param name="itemData">Item data which will apply to tab item view.</param>
397         /// <since_tizen> 6 </since_tizen>
398         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
399         [EditorBrowsable(EditorBrowsableState.Never)]
400         public void AddItem(DropDownDataItem itemData)
401         {
402             // Add item to adaptor, will be added to list via AddItemAt during OnUpdate()
403             int insertionPosition = adapter.GetItemCount();
404             adapter.InsertData(insertionPosition, itemData);
405         }
406
407         /// <summary>
408         /// Delete list item by index.
409         /// </summary>
410         /// <param name="index">Position index where will be deleted.</param>
411         /// <since_tizen> 6 </since_tizen>
412         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
413         [EditorBrowsable(EditorBrowsableState.Never)]
414         public void DeleteItem(int index)
415         {
416             if (index < 0 || index >= adapter?.GetItemCount()) return;
417             if (null == dropDownMenuFullList) return;
418
419             if (dropDownStyle.SelectedItemIndex == index)
420             {
421                 dropDownStyle.SelectedItemIndex = -1;
422             }
423             else if (dropDownStyle.SelectedItemIndex > index)
424             {
425                 dropDownStyle.SelectedItemIndex--;
426             }
427
428             adapter?.RemoveData(index);
429
430             if (index < dropDownMenuFullList.ChildCount)
431             {
432                 View childToRemove = dropDownMenuFullList.GetChildAt((uint)index);
433                 if (childToRemove)
434                 {
435                     childToRemove.TouchEvent -= ListItemTouchEvent;
436                     dropDownMenuFullList.Remove(childToRemove);
437                     dropDownMenuFullList?.Layout?.RequestLayout();
438                 }
439             }
440         }
441
442         /// <summary>
443         /// Insert list item by item data. The inserted item will be added to the special position by index automatically.
444         /// </summary>
445         /// <param name="item">Item data which will apply to tab item view.</param>
446         /// <param name="index">Position index where will be inserted.</param>
447         /// <since_tizen> 6 </since_tizen>
448         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
449         [EditorBrowsable(EditorBrowsableState.Never)]
450         public void InsertItem(DropDownDataItem item, int index)
451         {
452             if (index < 0 || index >= adapter.GetItemCount())
453             {
454                 return;
455             }
456
457             if (dropDownStyle.SelectedItemIndex >= index)
458             {
459                 dropDownStyle.SelectedItemIndex++;
460             }
461
462             adapter.InsertData(index, item);
463         }
464
465         /// <summary>
466         /// Add scroll bar to list.
467         /// </summary>
468         /// <param name="scrollBar">Scroll bar defined by user which will be added to list.</param>
469         /// <since_tizen> 6 </since_tizen>
470         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
471         [EditorBrowsable(EditorBrowsableState.Never)]
472         public void AttachScrollBar(ScrollBar scrollBar)
473         {
474             if (scrollableBase == null)
475             {
476                 return;
477             }
478             Tizen.Log.Error("DropDown", "Feature unsupported");
479         }
480
481         /// <summary>
482         /// Detach scroll bar to list.
483         /// </summary>
484         /// <since_tizen> 6 </since_tizen>
485         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
486         [EditorBrowsable(EditorBrowsableState.Never)]
487         public void DetachScrollBar()
488         {
489             if (scrollableBase == null)
490             {
491                 return;
492             }
493             Tizen.Log.Error("DropDown", "Feature unsupported");
494         }
495
496         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
497         [EditorBrowsable(EditorBrowsableState.Never)]
498         public override void ApplyStyle(ViewStyle viewStyle)
499         {
500             base.ApplyStyle(viewStyle);
501
502             DropDownStyle dropDownStyle = viewStyle as DropDownStyle;
503             if (null != dropDownStyle)
504             {
505                 if (null != dropDownStyle.Button)
506                 {
507                     Button.ApplyStyle(dropDownStyle.Button);
508                 }
509                 if (null != dropDownStyle.HeaderText)
510                 {
511                     HeaderText.ApplyStyle(dropDownStyle.HeaderText);
512                 }
513                 if (null != dropDownStyle.ListBackgroundImage)
514                 {
515                     ListBackgroundImage.ApplyStyle(dropDownStyle.ListBackgroundImage);
516                 }
517                 UpdateDropDown();
518             }
519         }
520
521         /// <summary>
522         /// Update DropDown by style.
523         /// </summary>
524         /// <since_tizen> 6 </since_tizen>
525         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
526         [EditorBrowsable(EditorBrowsableState.Never)]
527         protected void UpdateDropDown()
528         {
529             if (null == scrollableBase || null == listBackgroundImage || null == dropDownMenuFullList) return;
530             if (null == ListBackgroundImage.Size) return;
531             // Resize and position scrolling list within the drop down list container.  Can be used to position list in relation to the background image.
532             Size dropDownPaddingSize = new Size((dropDownStyle.ListPadding.Start + dropDownStyle.ListPadding.End), (dropDownStyle.ListPadding.Top + dropDownStyle.ListPadding.Bottom), 0);
533             scrollableBase.Size = ListBackgroundImage.Size - dropDownPaddingSize;
534             dropDownPaddingSize.Dispose();
535             scrollableBase.Position2D = new Position2D(dropDownStyle.ListPadding.Start, dropDownStyle.ListPadding.Top);
536
537             int listBackgroundImageX = 0;
538             int listBackgroundImageY = 0;
539             if (dropDownStyle.ListRelativeOrientation == ListOrientation.Left)
540             {
541                 listBackgroundImageX = (int)dropDownStyle.ListMargin.Start;
542                 listBackgroundImageY = (int)dropDownStyle.ListMargin.Top;
543             }
544             else if (dropDownStyle.ListRelativeOrientation == ListOrientation.Right)
545             {
546                 listBackgroundImageX = -(int)dropDownStyle.ListMargin.End;
547                 listBackgroundImageY = (int)dropDownStyle.ListMargin.Top;
548             }
549             listBackgroundImage.Position2D = new Position2D(listBackgroundImageX, listBackgroundImageY);
550             dropDownMenuFullList?.Layout?.RequestLayout();
551         }
552
553         /// <summary>
554         /// update.
555         /// </summary>
556         protected override void OnUpdate()
557         {
558             float buttonTextWidth = 0;
559             if (null != buttonText)
560             {
561                 buttonText.Text = Button.TextLabel.Text;
562                 buttonText.PointSize = Button.TextLabel.PointSize;
563                 buttonTextWidth = buttonText.NaturalSize.Width;
564             }
565             float fitWidth = (Button.Icon.Size?.Width ?? 48) + dropDownStyle.SpaceBetweenButtonTextAndIcon + buttonTextWidth;
566             fitWidth += (button.IconPadding.Start + button.IconPadding.End);
567             button.Size.Width = Math.Max(button.Size.Width, fitWidth);
568             RelayoutRequest();
569
570             int numberOfItemsToAdd = adapter.GetItemCount();
571
572             if (adapter.AdapterPurge == true)
573             {
574                 adapter.AdapterPurge = false;
575                 for (int i = 0; i < numberOfItemsToAdd; i++)
576                 {
577                     AddItemAt(adapter.GetData(i), i);
578                 }
579             }
580             // Set selection icon on View
581             if (dropDownStyle.SelectedItemIndex > 0)
582             {
583                 SetListItemToSelected((uint)dropDownStyle.SelectedItemIndex, selectedItemView);
584             }
585         }
586
587         /// <summary>
588         /// Dispose DropDown and all children on it.
589         /// </summary>
590         /// <param name="type">Dispose type.</param>
591         /// <since_tizen> 6 </since_tizen>
592         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
593         [EditorBrowsable(EditorBrowsableState.Never)]
594         protected override void Dispose(DisposeTypes type)
595         {
596             if (disposed)
597             {
598                 return;
599             }
600
601             if (type == DisposeTypes.Explicit)
602             {
603                 Utility.Dispose(headerText);
604                 Utility.Dispose(buttonText);
605                 Utility.Dispose(button);
606                 Utility.Dispose(scrollableBase);
607                 Utility.Dispose(dropDownMenuFullList);
608                 Utility.Dispose(listBackgroundImage);
609             }
610
611             base.Dispose(type);
612         }
613
614         /// <summary>
615         /// Get DropDown style.
616         /// </summary>
617         /// <returns>The default dropdown style.</returns>
618         /// <since_tizen> 6 </since_tizen>
619         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
620         [EditorBrowsable(EditorBrowsableState.Never)]
621         protected override ViewStyle CreateViewStyle()
622         {
623             return new DropDownStyle();
624         }
625
626         private void AddItemAt(DropDownDataItem itemData, int index)
627         {
628             ViewHolder viewHolder = adapter.OnCreateViewHolder();
629             if (!viewHolder.IsBound)
630             {
631                 adapter.BindViewHolder(viewHolder, index);
632                 viewHolder.IsBound = true;
633             }
634
635             if (tapGestureDetector == null)
636             {
637                 tapGestureDetector = new TapGestureDetector();
638             }
639             View view = viewHolder.ItemView;
640             view.ApplyStyle(itemData.itemDataStyle);
641             view.TouchEvent += ListItemTouchEvent;
642             dropDownMenuFullList.Add(view);
643         }
644
645         private void OnClickEvent(object sender, ItemClickEventArgs e)
646         {
647             ItemClickEvent?.Invoke(sender, e);
648         }
649
650         private void CreateButtonText()
651         {
652             if (null == buttonText)
653             {
654                 buttonText = new TextLabel();
655             }
656         }
657
658         private void CreateButton()
659         {
660             if (null == button)
661             {
662                 button = new Button()
663                 {
664                     ParentOrigin = NUI.ParentOrigin.CenterLeft,
665                     PivotPoint = NUI.PivotPoint.CenterLeft,
666                     PositionUsesPivotPoint = true,
667                     HeightResizePolicy = ResizePolicyType.FitToChildren,
668                     IconRelativeOrientation = Button.IconOrientation.Right,
669                 };
670                 button.Name = "DropDownButton";
671                 button.ClickEvent += ButtonClickEvent;
672                 Add(button);
673             }
674         }
675
676         private void SetUpListContainer()
677         {
678             LinearLayout linear = new LinearLayout()
679             {
680                 LinearOrientation = LinearLayout.Orientation.Vertical,
681             };
682
683             dropDownMenuFullList = new View()
684             {
685                 Layout = linear,
686                 Name = "DropDownMenuList",
687                 WidthSpecification = LayoutParamPolicies.MatchParent,
688                 HeightSpecification = LayoutParamPolicies.WrapContent,
689                 Focusable = true,
690             };
691
692             scrollableBase = new ScrollableBase()
693             {
694                 Name = "Scrollable",
695             };
696             scrollableBase.Add(dropDownMenuFullList);
697
698             listBackgroundImage.Add(scrollableBase);
699             listBackgroundImage.Hide();
700         }
701
702         private View GetViewFromIndex(uint index)
703         {
704             if ((index < dropDownMenuFullList.ChildCount) && (index >= 0))
705             {
706                 return dropDownMenuFullList.GetChildAt(index);
707             }
708             else
709             {
710                 return null;
711             }
712         }
713
714         private void SetListItemToSelected(DropDownItemView view)
715         {
716             if (dropDownMenuFullList == null || view == null || view == selectedItemView)
717             {
718                 return;
719             }
720
721             uint newSelectedIndex = 0;
722             for (; newSelectedIndex < dropDownMenuFullList.ChildCount; newSelectedIndex++)
723             {
724                 var itemView = dropDownMenuFullList.GetChildAt(newSelectedIndex) as DropDownItemView;
725                 if (itemView == view)
726                 {
727                     SetListItemToSelected(newSelectedIndex, view);
728                     return;
729                 }
730             }
731         }
732
733         private void SetListItemToSelected(uint index)
734         {
735             if (dropDownMenuFullList == null || index == dropDownStyle.SelectedItemIndex)
736             {
737                 return;
738             }
739
740             SetListItemToSelected(index, GetViewFromIndex(index) as DropDownItemView);
741         }
742
743         private void SetListItemToSelected(uint index, DropDownItemView view)
744         {
745             if (adapter == null)
746             {
747                 return;
748             }
749
750             if (selectedItemView != null)
751             {
752                 selectedItemView.IsSelected = false;
753                 adapter.GetData(dropDownStyle.SelectedItemIndex).IsSelected = false;
754             }
755
756             if (view == null || index >= dropDownMenuFullList.ChildCount)
757             {
758                 dropDownStyle.SelectedItemIndex = -1;
759                 selectedItemView = null;
760                 return;
761             }
762
763             dropDownStyle.SelectedItemIndex = (int)index;
764             selectedItemView = view;
765             selectedItemView.IsSelected = true;
766             adapter.GetData(dropDownStyle.SelectedItemIndex).IsSelected = true;
767             dropDownMenuFullList.Layout?.RequestLayout();
768         }
769
770         private bool ListItemTouchEvent(object sender, TouchEventArgs e)
771         {
772             PointStateType state = e.Touch.GetState(0);
773             DropDownItemView touchedView = sender as DropDownItemView;
774             if (touchedView == null)
775             {
776                 return true;
777             }
778
779             touchedView.OnTouch(e.Touch); // Handle control state change
780
781             switch (state)
782             {
783                 case PointStateType.Down:
784                     itemPressed = true;  // if matched with a Up then a click event.
785                     break;
786                 case PointStateType.Motion:
787                     itemPressed = false;
788                     break;
789                 case PointStateType.Up:
790                     if (touchedView != null)
791                     {
792                         if (itemPressed)  // if Down was previously sent without motion (Scrolling) in-between then a clicked event occurred.
793                         {
794                             // List item clicked
795                             Console.WriteLine("Tapped{0}", touchedView.Name);
796                             SetListItemToSelected(touchedView);
797                             button.Text = touchedView.Text;
798                             button.Show();
799                             listBackgroundImage.Hide();
800                         }
801                     }
802                     break;
803                 default:
804                     break;
805             }
806             return true;
807         }
808
809         private void ButtonClickEvent(object sender, Button.ClickEventArgs e)
810         {
811             button.Hide();
812             listBackgroundImage.Show();
813             dropDownMenuFullList?.Layout?.RequestLayout();
814             listBackgroundImage.RaiseToTop();
815         }
816
817         #endregion
818
819         #region ItemClickEventArgs
820         /// <summary>
821         /// ItemClickEventArgs is a class to record item click event arguments which will sent to user.
822         /// </summary>
823         /// <since_tizen> 6 </since_tizen>
824         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
825         [EditorBrowsable(EditorBrowsableState.Never)]
826         public class ItemClickEventArgs : EventArgs
827         {
828             /// <summary> Clicked item index of DropDown's list </summary>
829             /// <since_tizen> 6 </since_tizen>
830             /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
831             [EditorBrowsable(EditorBrowsableState.Never)]
832             public int Index { get; set; }
833             /// <summary> Clicked item text string of DropDown's list </summary>
834             /// <since_tizen> 6 </since_tizen>
835             /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
836             [EditorBrowsable(EditorBrowsableState.Never)]
837             public string Text { get; set; }
838         }
839         #endregion
840
841         #region ViewHolder
842
843         /// <summary>
844         /// A ViewHolder is a class that holds a View created from DropDownListBridge data.
845         /// </summary>
846         /// <since_tizen> 6 </since_tizen>
847         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
848         [EditorBrowsable(EditorBrowsableState.Never)]
849         public class ViewHolder
850         {
851             /// <summary>
852             /// ViewHolder constructor.
853             /// </summary>
854             /// <param name="itemView">View</param>
855             /// <since_tizen> 6 </since_tizen>
856             /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
857             [EditorBrowsable(EditorBrowsableState.Never)]
858             public ViewHolder(View itemView)
859             {
860                 ItemView = itemView ?? throw new ArgumentNullException(nameof(itemView), "itemView may not be null");
861             }
862
863             /// <summary>
864             /// Returns the view.
865             /// </summary>
866             /// <since_tizen> 6 </since_tizen>
867             /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
868             [EditorBrowsable(EditorBrowsableState.Never)]
869             public View ItemView { get; }
870
871             internal bool IsBound { get; set; }
872         }
873
874         #endregion
875     }
876 }