c8c2c45a42d7ba5d37b4fd844dc858f4bc6b4517
[platform/core/csapi/tizenfx.git] / src / ElmSharp / ElmSharp / GenList.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
20 namespace ElmSharp
21 {
22     /// <summary>
23     /// Enumeration for setting genlist item type.
24     /// </summary>
25     public enum GenListItemType
26     {
27         /// <summary>
28         /// if Normal is set then this item is normal item.
29         /// </summary>
30         Normal = 0,
31
32         /// <summary>
33         /// If tree is set then this item is displayed as an item that is able to expand and have child items.
34         /// </summary>
35         Tree = (1 << 0),
36
37         /// <summary>
38         /// if Group is set then this item is group index item that is displayed at the top until the next group comes.
39         /// </summary>
40         Group = (1 << 1),
41     }
42
43     /// <summary>
44     /// Enumeration for setting genlist's resizing behavior, transverse axis scrolling and items cropping.
45     /// </summary>
46     public enum GenListMode
47     {
48         /// <summary>
49         /// The genlist won't set any of its size hints to inform how a possible container should resize it.
50         /// Then, if it's not created as a "resize object", it might end with zeroed dimensions.
51         /// The genlist will respect the container's geometry and, if any of its items won't fit into its transverse axis, one won't be able to scroll it in that direction.
52         /// </summary>
53         Compress = 0,
54
55         /// <summary>
56         /// This is the same as Compress, with the exception that if any of its items won't fit into its transverse axis, one will be able to scroll it in that direction.
57         /// </summary>
58         Scroll,
59
60         /// <summary>
61         /// Sets a minimum size hint on the genlist object, so that containers may respect it (and resize itself to fit the child properly).
62         /// More specifically, a minimum size hint will be set for its transverse axis, so that the largest item in that direction fits well.
63         /// This is naturally bound by the genlist object's maximum size hints, set externally.
64         /// </summary>
65         Limit,
66
67         /// <summary>
68         /// Besides setting a minimum size on the transverse axis, just like on Limit, the genlist will set a minimum size on th longitudinal axis, trying to reserve space to all its children to be visible at a time.
69         /// This is naturally bound by the genlist object's maximum size hints, set externally.
70         /// </summary>
71         Expand
72     }
73
74     /// <summary>
75     /// It inherits System.EventArgs.
76     /// It contains Item which is <see cref="GenListItem"/> type.
77     /// All events of GenList contain GenListItemEventArgs as a parameter.
78     /// </summary>
79     public class GenListItemEventArgs : EventArgs
80     {
81         /// <summary>
82         /// Gets or sets GenList item. The return type is <see cref="GenListItem"/>.
83         /// </summary>
84         public GenListItem Item { get; set; }
85
86         internal static GenListItemEventArgs CreateFromSmartEvent(IntPtr data, IntPtr obj, IntPtr info)
87         {
88             GenListItem item = ItemObject.GetItemByHandle(info) as GenListItem;
89             return new GenListItemEventArgs() { Item = item };
90         }
91     }
92
93     /// <summary>
94     /// Enumeration that defines where to position the item in the genlist.
95     /// </summary>
96     public enum ScrollToPosition
97     {
98         /// <summary>
99         /// Scrolls to nowhere.
100         /// </summary>
101         None = 0,
102
103         /// <summary>
104         /// Scrolls to the nearest viewport.
105         /// </summary>
106         In = (1 << 0),
107
108         /// <summary>
109         /// Scrolls to the top of the viewport.
110         /// </summary>
111         Top = (1 << 1),
112
113         /// <summary>
114         /// Scrolls to the middle of the viewport.
115         /// </summary>
116         Middle = (1 << 2),
117
118         /// <summary>
119         /// Scrolls to the bottom of the viewport.
120         /// </summary>
121         Bottom = (1 << 3)
122     }
123
124     /// <summary>
125     /// It inherits <see cref="Layout"/>.
126     /// The GenList is a widget that aims to have more expansive list than the simple <see cref="List"/> in ElmSharp that could have more flexible items and allow many more entries while still being fast and low on memory usage.
127     /// At the same time it was also made to be able to do tree structures.
128     /// But the price to pay is more complexity when it comes to usage.
129     /// If all you want is a simple list with icons and a single text, use the <see cref="List"/> widget.
130     /// </summary>
131     public class GenList : Layout, IScrollable
132     {
133         ScrollableAdapter _scroller;
134         HashSet<GenListItem> _children = new HashSet<GenListItem>();
135
136         SmartEvent<GenListItemEventArgs> _selected;
137         SmartEvent<GenListItemEventArgs> _unselected;
138         SmartEvent<GenListItemEventArgs> _activated;
139         SmartEvent<GenListItemEventArgs> _pressed;
140         SmartEvent<GenListItemEventArgs> _released;
141         SmartEvent<GenListItemEventArgs> _doubleClicked;
142         SmartEvent<GenListItemEventArgs> _expanded;
143         SmartEvent<GenListItemEventArgs> _realized;
144         SmartEvent<GenListItemEventArgs> _unrealized;
145         SmartEvent<GenListItemEventArgs> _longpressed;
146         SmartEvent<GenListItemEventArgs> _moved;
147         SmartEvent<GenListItemEventArgs> _movedAfter;
148         SmartEvent<GenListItemEventArgs> _movedBefore;
149         SmartEvent _scrollAnimationStarted;
150         SmartEvent _scrollAnimationStopped;
151         SmartEvent _changed;
152
153         /// <summary>
154         /// Creates and initializes a new instance of the GenList class.
155         /// </summary>
156         /// <param name="parent">The parent is a given container which will be attached by GenList as a child. It's <see cref="EvasObject"/> type.</param>
157         public GenList(EvasObject parent) : base(parent)
158         {
159         }
160
161         /// <summary>
162         /// Creates and initializes a new instance of GenList class.
163         /// </summary>
164         protected GenList() : base()
165         {
166         }
167
168         /// <summary>
169         /// Gets or sets whether the homogeneous mode is enabled.
170         /// </summary>
171         /// <remarks>
172         /// If true, the genlist items have same height and width.
173         /// </remarks>
174         public bool Homogeneous
175         {
176             get
177             {
178                 return Interop.Elementary.elm_genlist_homogeneous_get(RealHandle);
179             }
180             set
181             {
182                 Interop.Elementary.elm_genlist_homogeneous_set(RealHandle, value);
183             }
184         }
185
186         /// <summary>
187         /// Gets or sets the horizontal stretching mode. This mode used for sizing items horizontally.
188         /// The default value is <see cref="GenListMode.Scroll"/> which means that if items are too wide to fit, the scroller scrolls horizontally.
189         /// If set <see cref="GenListMode.Compress"/> which means that the item width is fixed (restricted to a minimum of) to the list width when calculating its size in order to allow the height to be calculated based on it.
190         /// If set <see cref="GenListMode.Limit"/> which means that items are expanded to the viewport width and limited to that size.
191         /// if set <see cref="GenListMode.Expand"/> which means that genlist try to reserve space to all its items to be visible at a time.
192         /// </summary>
193         /// <remarks>
194         /// Compress makes genlist resize slower as it recalculates every item height again whenever the list width changes.
195         /// The homogeneous mode is so that all items in the genlist are of the same width/height. With Compress, genlist items are initialized fast.
196         /// However, there are no sub-objects in the genlist which can be on the flying resizable (such as TEXTBLOCK).
197         /// If so, then some dynamic resizable objects in the genlist would not be diplayed properly.
198         /// </remarks>
199         public GenListMode ListMode
200         {
201             get
202             {
203                 return (GenListMode)Interop.Elementary.elm_genlist_mode_get(RealHandle);
204             }
205             set
206             {
207                 Interop.Elementary.elm_genlist_mode_set(RealHandle, (int)value);
208             }
209         }
210
211         /// <summary>
212         /// Gets the first item in the genlist.
213         /// </summary>
214         public GenListItem FirstItem
215         {
216             get
217             {
218                 IntPtr handle = Interop.Elementary.elm_genlist_first_item_get(RealHandle);
219                 return ItemObject.GetItemByHandle(handle) as GenListItem;
220             }
221         }
222
223         /// <summary>
224         /// Gets the last item in the genlist.
225         /// </summary>
226         public GenListItem LastItem
227         {
228             get
229             {
230                 IntPtr handle = Interop.Elementary.elm_genlist_last_item_get(RealHandle);
231                 return ItemObject.GetItemByHandle(handle) as GenListItem;
232             }
233         }
234
235         /// <summary>
236         /// Gets or sets the reorder mode.
237         /// After turning on the reorder mode, longpress on a normal item triggers reordering of the item.
238         /// You can move the item up and down. However, reordering does not work with group items.
239         /// </summary>
240         public bool ReorderMode
241         {
242             get
243             {
244                 return Interop.Elementary.elm_genlist_reorder_mode_get(RealHandle);
245             }
246             set
247             {
248                 Interop.Elementary.elm_genlist_reorder_mode_set(RealHandle, value);
249             }
250         }
251
252         /// <summary>
253         /// Gets or set the maximum number of items within an item block.
254         /// </summary>
255         public int BlockCount
256         {
257             get
258             {
259                 return Interop.Elementary.elm_genlist_block_count_get(RealHandle);
260             }
261             set
262             {
263                 Interop.Elementary.elm_genlist_block_count_set(RealHandle, value);
264             }
265         }
266
267         /// <summary>
268         /// Gets or sets whether the genlist items should be highlighted when an item is selected.
269         /// </summary>
270         public bool IsHighlight
271         {
272             get
273             {
274                 return Interop.Elementary.elm_genlist_highlight_mode_get(RealHandle);
275             }
276             set
277             {
278                 Interop.Elementary.elm_genlist_highlight_mode_set(RealHandle, value);
279             }
280         }
281
282         /// <summary>
283         /// Gets or sets the timeout in seconds for the longpress event.
284         /// </summary>
285         public double LongPressTimeout
286         {
287             get
288             {
289                 return Interop.Elementary.elm_genlist_longpress_timeout_get(RealHandle);
290             }
291             set
292             {
293                 Interop.Elementary.elm_genlist_longpress_timeout_set(RealHandle, value);
294             }
295         }
296
297         /// <summary>
298         /// Gets or Sets focus upon items selection mode.
299         /// </summary>
300         /// <remarks>
301         /// When enabled, every selection of an item inside the <see cref="GenList"/> will automatically set focus to its first focusable widget from the left.
302         /// This is true of course if the selection was made by clicking an unfocusable area in an item or selecting it with a key movement.
303         /// Clicking on a focusable widget inside an item will couse this particular item to get focus as usual.
304         /// </remarks>
305         public bool FocusOnSelection
306         {
307             get
308             {
309                 return Interop.Elementary.elm_genlist_focus_on_selection_get(RealHandle);
310             }
311             set
312             {
313                 Interop.Elementary.elm_genlist_focus_on_selection_set(RealHandle, value);
314             }
315         }
316
317         /// <summary>
318         /// Gets or sets whether enable multi-selection in the genlist.
319         /// </summary>
320         public bool IsMultiSelection
321         {
322             get
323             {
324                 return Interop.Elementary.elm_genlist_multi_select_get(RealHandle);
325             }
326             set
327             {
328                 Interop.Elementary.elm_genlist_multi_select_set(RealHandle, value);
329             }
330         }
331
332         /// <summary>
333         /// Gets the selected item in a given genlist widget.
334         /// </summary>
335         public GenListItem SelectedItem
336         {
337             get
338             {
339                 IntPtr handle = Interop.Elementary.elm_genlist_selected_item_get(RealHandle);
340                 return ItemObject.GetItemByHandle(handle) as GenListItem;
341             }
342         }
343
344         /// <summary>
345         /// Gets or sets the genlist select mode by <see cref="GenItemSelectionMode"/>.
346         /// </summary>
347         public GenItemSelectionMode SelectionMode
348         {
349             get
350             {
351                 return (GenItemSelectionMode)Interop.Elementary.elm_genlist_select_mode_get(RealHandle);
352             }
353             set
354             {
355                 Interop.Elementary.elm_genlist_select_mode_set(RealHandle, (int)value);
356             }
357         }
358
359         /// <summary>
360         /// Gets count of items in a this genlist widget
361         /// </summary>
362         public int Count
363         {
364             get
365             {
366                 return Interop.Elementary.elm_genlist_items_count(RealHandle);
367             }
368         }
369
370         /// <summary>
371         /// ItemSelected is raised when a new genlist item is selected.
372         /// </summary>
373         public event EventHandler<GenListItemEventArgs> ItemSelected;
374
375         /// <summary>
376         /// ItemUnselected is raised when the genlist item is Unselected.
377         /// </summary>
378         public event EventHandler<GenListItemEventArgs> ItemUnselected;
379
380         /// <summary>
381         /// ItemPressed is raised when a new genlist item is pressed.
382         /// </summary>
383         public event EventHandler<GenListItemEventArgs> ItemPressed;
384
385         /// <summary>
386         /// ItemReleased is raised when a new genlist item is released.
387         /// </summary>
388         public event EventHandler<GenListItemEventArgs> ItemReleased;
389
390         /// <summary>
391         /// ItemActivated is raised when a new genlist item is double clicked or pressed (enter|return|spacebar).
392         /// </summary>
393         public event EventHandler<GenListItemEventArgs> ItemActivated;
394
395         /// <summary>
396         /// ItemDoubleClicked is raised when a new genlist item is double clicked.
397         /// </summary>
398         public event EventHandler<GenListItemEventArgs> ItemDoubleClicked;
399
400         /// <summary>
401         /// ItemExpanded is raised when a new genlist item is indicated to expand.
402         /// </summary>
403         public event EventHandler<GenListItemEventArgs> ItemExpanded;
404
405         /// <summary>
406         /// ItemRealized is raised when a new genlist item is created as a real object.
407         /// </summary>
408         public event EventHandler<GenListItemEventArgs> ItemRealized;
409
410         /// <summary>
411         /// ItemUnrealized is raised when a new genlist item is unrealized.
412         /// After calling unrealize, the item's content objects are deleted and the item object itself is deleted or is put into a floating cache.
413         /// </summary>
414         public event EventHandler<GenListItemEventArgs> ItemUnrealized;
415
416         /// <summary>
417         /// ItemLongPressed is raised when a genlist item is pressed for a certain amount of time. By default it's 1 second.
418         /// </summary>
419         public event EventHandler<GenListItemEventArgs> ItemLongPressed;
420
421         /// <summary>
422         /// ItemMoved is raised when a genlist item is moved in the reorder mode.
423         /// </summary>
424         public event EventHandler<GenListItemEventArgs> ItemMoved;
425
426         /// <summary>
427         /// ItemMovedAfter is raised when a genlist item is moved after another item in the reorder mode.
428         /// To get the relative previous item, use <see cref="GenListItem.Previous"/>.
429         /// </summary>
430         public event EventHandler<GenListItemEventArgs> ItemMovedAfter;
431
432         /// <summary>
433         /// ItemMovedBefore is raised when a genlist item is moved before another item in the reorder mode.
434         /// To get the relative next item, use <see cref="GenListItem.Next"/>.
435         /// </summary>
436         public event EventHandler<GenListItemEventArgs> ItemMovedBefore;
437
438         /// <summary>
439         /// Changed is raised when genlist is changed.
440         /// </summary>
441         public event EventHandler Changed
442         {
443             add { _changed.On += value; }
444             remove { _changed.On -= value; }
445         }
446
447         /// <summary>
448         /// ScrollAnimationStarted is raised when scrolling animation has started.
449         /// </summary>
450         public event EventHandler ScrollAnimationStarted
451         {
452             add { _scrollAnimationStarted.On += value; }
453             remove { _scrollAnimationStarted.On -= value; }
454         }
455
456         /// <summary>
457         /// ScrollAnimationStopped is raised when scrolling animation has stopped.
458         /// </summary>
459         public event EventHandler ScrollAnimationStopped
460         {
461             add { _scrollAnimationStopped.On += value; }
462             remove { _scrollAnimationStopped.On -= value; }
463         }
464
465         /// <summary>
466         /// Appends a new item to the end of a given genlist widget.
467         /// </summary>
468         /// <param name="itemClass">The itemClass defines how to display the data.</param>
469         /// <param name="data">The item data.</param>
470         /// <returns>Return a new added genlist item that contains data and itemClass.</returns>
471         /// <seealso cref="GenItemClass"/>
472         /// <seealso cref="GenListItem"/>
473         public GenListItem Append(GenItemClass itemClass, object data)
474         {
475             return Append(itemClass, data, GenListItemType.Normal);
476         }
477
478         /// <summary>
479         /// Appends a new item with <see cref="GenListItemType"/> to the end of a given genlist widget.
480         /// </summary>
481         /// <param name="itemClass">The itemClass defines how to display the data.</param>
482         /// <param name="data">The item data.</param>
483         /// <param name="type">The genlist item type.</param>
484         /// <returns>Return a new added genlist item that contains data and itemClass.</returns>
485         public GenListItem Append(GenItemClass itemClass, object data, GenListItemType type)
486         {
487             return Append(itemClass, data, type, null);
488         }
489
490         /// <summary>
491         /// Appends a new item with <see cref="GenListItemType"/> to the end of a given genlist widget or the end of the children list if the parent is given.
492         /// </summary>
493         /// <param name="itemClass">The itemClass defines how to display the data.</param>
494         /// <param name="data">The item data.</param>
495         /// <param name="type">The genlist item type.</param>
496         /// <param name="parent">The parent item, otherwise null if there is no parent item.</param>
497         /// <returns>Return a new added genlist item that contains data and itemClass.</returns>
498         public GenListItem Append(GenItemClass itemClass, object data, GenListItemType type, GenListItem parent)
499         {
500             GenListItem item = new GenListItem(data, itemClass);
501             IntPtr handle = Interop.Elementary.elm_genlist_item_append(RealHandle, itemClass.UnmanagedPtr, (IntPtr)item.Id, parent, (int)type, null, (IntPtr)item.Id);
502             item.Handle = handle;
503             AddInternal(item);
504             return item;
505         }
506
507         /// <summary>
508         /// Prepends a new item to the beginning of a given genlist widget.
509         /// </summary>
510         /// <param name="itemClass">The itemClass defines how to display the data.</param>
511         /// <param name="data">The item data.</param>
512         /// <returns>Return a new added genlist item that contains data and itemClass.</returns>
513         public GenListItem Prepend(GenItemClass itemClass, object data)
514         {
515             return Prepend(itemClass, data, GenListItemType.Normal);
516         }
517
518         /// <summary>
519         /// Prepends a new item with <see cref="GenListItemType"/> to the beginning of a given genlist widget.
520         /// </summary>
521         /// <param name="itemClass">The itemClass defines how to display the data.</param>
522         /// <param name="data">The item data.</param>
523         /// <param name="type">The genlist item type.</param>
524         /// <returns>Return a new added genlist item that contains data and itemClass.</returns>
525         public GenListItem Prepend(GenItemClass itemClass, object data, GenListItemType type)
526         {
527             return Prepend(itemClass, data, type, null);
528         }
529
530         /// <summary>
531         /// Prepends a new item with <see cref="GenListItemType"/> to the beginning of a given genlist widget or the beginning of the children list if the parent is given.
532         /// </summary>
533         /// <param name="itemClass">The itemClass defines how to display the data.</param>
534         /// <param name="data">The item data.</param>
535         /// <param name="type">The genlist item type.</param>
536         /// <param name="parent">The parent item, otherwise null if there is no parent item.</param>
537         /// <returns>Return a new added genlist item that contains data and itemClass.</returns>
538         public GenListItem Prepend(GenItemClass itemClass, object data, GenListItemType type, GenListItem parent)
539         {
540             GenListItem item = new GenListItem(data, itemClass);
541             IntPtr handle = Interop.Elementary.elm_genlist_item_prepend(RealHandle, itemClass.UnmanagedPtr, (IntPtr)item.Id, parent, (int)type, null, (IntPtr)item.Id);
542             item.Handle = handle;
543             AddInternal(item);
544             return item;
545         }
546
547         /// <summary>
548         /// Inserts an item before another item in a genlist widget.
549         /// It is the same tree level or group as the item before which it is inserted.????
550         /// </summary>
551         /// <param name="itemClass">The itemClass defines how to display the data.</param>
552         /// <param name="data">The item data.</param>
553         /// <param name="before">The item before which to place this new one.</param>
554         /// <returns>Return a new added genlist item that contains data and itemClass.</returns>
555         public GenListItem InsertBefore(GenItemClass itemClass, object data, GenListItem before)
556         {
557             return InsertBefore(itemClass, data, before, GenListItemType.Normal);
558         }
559
560         /// <summary>
561         /// Inserts an item with <see cref="GenListItemType"/> before another item in a genlist widget.
562         /// It is the same tree level or group as the item before which it is inserted.????
563         /// </summary>
564         /// <param name="itemClass">The itemClass defines how to display the data.</param>
565         /// <param name="data">The item data.</param>
566         /// <param name="before">The item before which to place this new one.</param>
567         /// <param name="type">The genlist item type.</param>
568         /// <returns>Return a new added genlist item that contains data and itemClass.</returns>
569         public GenListItem InsertBefore(GenItemClass itemClass, object data, GenListItem before, GenListItemType type)
570         {
571             return InsertBefore(itemClass, data, before, type, null);
572         }
573
574         /// <summary>
575         /// Inserts an item with <see cref="GenListItemType"/> before another item under a parent in a genlist widget.
576         /// </summary>
577         /// <param name="itemClass">The itemClass defines how to display the data.</param>
578         /// <param name="data">The item data.</param>
579         /// <param name="before">The item before which to place this new one.</param>
580         /// <param name="type">The genlist item type.</param>
581         /// <param name="parent">The parent item, otherwise null if there is no parent item.</param>
582         /// <returns>Return a new added genlist item that contains data and itemClass.</returns>
583         public GenListItem InsertBefore(GenItemClass itemClass, object data, GenListItem before, GenListItemType type, GenListItem parent)
584         {
585             GenListItem item = new GenListItem(data, itemClass);
586             // insert before the `before` list item
587             IntPtr handle = Interop.Elementary.elm_genlist_item_insert_before(
588                 RealHandle, // genlist handle
589                 itemClass.UnmanagedPtr, // item class
590                 (IntPtr)item.Id, // data
591                 parent, // parent
592                 before, // before
593                 (int)type, // item type
594                 null, // select callback
595                 (IntPtr)item.Id); // callback data
596             item.Handle = handle;
597             AddInternal(item);
598             return item;
599         }
600
601         /// <summary>
602         /// Inserts an item with <see cref="GenListItemType"/> after another item under a parent in a genlist widget.
603         /// </summary>
604         /// <param name="itemClass">The itemClass defines how to display the data.</param>
605         /// <param name="data">The item data.</param>
606         /// <param name="after">The item after which to place this new one.</param>
607         /// <param name="type">The genlist item type.</param>
608         /// <param name="parent">The parent item, otherwise null if there is no parent item.</param>
609         /// <returns>Return a new added genlist item that contains data and itemClass.</returns>
610         public GenListItem InsertAfter(GenItemClass itemClass, object data, GenListItem after, GenListItemType type, GenListItem parent)
611         {
612             GenListItem item = new GenListItem(data, itemClass);
613             // insert before the `before` list item
614             IntPtr handle = Interop.Elementary.elm_genlist_item_insert_before(
615                 RealHandle, // genlist handle
616                 itemClass.UnmanagedPtr, // item class
617                 (IntPtr)item.Id, // data
618                 parent, // parent
619                 after, // after
620                 (int)type, // item type
621                 null, // select callback
622                 (IntPtr)item.Id); // callback data
623             item.Handle = handle;
624             AddInternal(item);
625             return item;
626         }
627
628         /// <summary>
629         /// Insert an item in a genlist widget using a user-defined sort function.
630         /// </summary>
631         /// <param name="itemClass">The itemClass defines how to display the data.</param>
632         /// <param name="data">The item data.</param>
633         /// <param name="comparison">User defined comparison function that defines the sort order based on genlist item and its data.</param>
634         /// <param name="type">The genlist item type.</param>
635         /// <param name="parent">The parent item, otherwise null if there is no parent item.</param>
636         /// <returns>Return a genlist item that contains data and itemClass.</returns>
637         public GenListItem InsertSorted(GenItemClass itemClass, object data, Comparison<object> comparison, GenListItemType type, GenListItem parent)
638         {
639             GenListItem item = new GenListItem(data, itemClass);
640
641             Interop.Elementary.Eina_Compare_Cb compareCallback = (handle1, handle2) =>
642             {
643                 GenListItem first = (ItemObject.GetItemByHandle(handle1) as GenListItem) ?? item;
644                 GenListItem second = (ItemObject.GetItemByHandle(handle2) as GenListItem) ?? item;
645                 return comparison(first.Data, second.Data);
646             };
647
648             IntPtr handle = Interop.Elementary.elm_genlist_item_sorted_insert(
649                 RealHandle, // genlist handle
650                 itemClass.UnmanagedPtr, // item clas
651                 (IntPtr)item.Id, // data
652                 parent, // parent
653                 (int)type, // item type
654                 compareCallback, // compare callback
655                 null, //select callback
656                 (IntPtr)item.Id); // callback data
657             item.Handle = handle;
658             AddInternal(item);
659             return item;
660         }
661
662         /// <summary>
663         /// Shows the given item with position type in a genlist.
664         /// When animated is true, genlist will jump to the given item and display it (by animatedly scrolling), if it is not fully visible. This may use animation and may take some time.
665         /// When animated is false, genlist will jump to the given item and display it (by jumping to that position), if it is not fully visible.
666         /// </summary>
667         /// <param name="item">The item to display.</param>
668         /// <param name="position">The position to show the given item to <see cref="ScrollToPosition"/>.</param>
669         /// <param name="animated">The animated indicates how to display the item, by scrolling or by jumping.</param>
670         public void ScrollTo(GenListItem item, ScrollToPosition position, bool animated)
671         {
672             if (animated)
673             {
674                 Interop.Elementary.elm_genlist_item_bring_in(item.Handle, (Interop.Elementary.Elm_Genlist_Item_Scrollto_Type)position);
675             }
676             else
677             {
678                 Interop.Elementary.elm_genlist_item_show(item.Handle, (Interop.Elementary.Elm_Genlist_Item_Scrollto_Type)position);
679             }
680         }
681
682         /// <summary>
683         /// Updates the content of all the realized items.
684         /// This updates all the realized items by calling all the <see cref="GenItemClass"/> again to get the content, text and states.
685         /// Use this when the original item data has changed and the changes are desired to reflect.
686         /// To update just one item, use <see cref="GenListItem.Update"/>.
687         /// </summary>
688         /// <seealso cref="GenListItem.Update"/>
689         public void UpdateRealizedItems()
690         {
691             Interop.Elementary.elm_genlist_realized_items_update(RealHandle);
692         }
693
694         /// <summary>
695         /// Removes all items from a given genlist widget.
696         /// This removes (and deletes) all items in obj, making it empty.
697         /// To delete just one item, use <see cref="ItemObject.Delete"/>.
698         /// </summary>
699         /// <seealso cref="ItemObject.Delete"/>
700         public void Clear()
701         {
702             Interop.Elementary.elm_genlist_clear(RealHandle);
703         }
704
705         /// <summary>
706         /// Get the item that is at the x, y canvas coords.
707         /// </summary>
708         /// <param name="x">The input x coordinate</param>
709         /// <param name="y">The input y coordinate</param>
710         /// <param name="pos">The position relative to the item returned here
711         ///  -1, 0, or 1, depending on whether the coordinate is on the upper portion of that item (-1), in the middle section (0), or on the lower part (1).
712         /// </param>
713         /// <returns></returns>
714         public GenListItem GetItemByPosition(int x, int y, out int pos)
715         {
716             IntPtr handle = Interop.Elementary.elm_genlist_at_xy_item_get(RealHandle, x, y, out pos);
717             return ItemObject.GetItemByHandle(handle) as GenListItem;
718         }
719
720         /// <summary>
721         /// Gets the nth item in a given genlist widget, placed at position nth, in its internal items list.
722         /// </summary>
723         /// <param name="index">The number of the item to grab (0 being the first)</param>
724         /// <returns></returns>
725         public GenListItem GetItemByIndex(int index)
726         {
727             IntPtr handle = Interop.Elementary.elm_genlist_nth_item_get(RealHandle, index);
728             return ItemObject.GetItemByHandle(handle) as GenListItem;
729         }
730
731         /// <summary>
732         /// The callback of Unrealize Event
733         /// </summary>
734         protected override void OnRealized()
735         {
736             base.OnRealized();
737             ListMode = GenListMode.Compress;
738             InitializeSmartEvent();
739         }
740
741         /// <summary>
742         /// Creates a widget handle.
743         /// </summary>
744         /// <param name="parent">Parent EvasObject</param>
745         /// <returns>Handle IntPtr</returns>
746         protected override IntPtr CreateHandle(EvasObject parent)
747         {
748             IntPtr handle = Interop.Elementary.elm_layout_add(parent.Handle);
749             Interop.Elementary.elm_layout_theme_set(handle, "layout", "elm_widget", "default");
750
751             RealHandle = Interop.Elementary.elm_genlist_add(handle);
752             Interop.Elementary.elm_object_part_content_set(handle, "elm.swallow.content", RealHandle);
753
754             _scroller = new ScrollableAdapter(this);
755
756             return handle;
757         }
758
759         #region IScroller Implementation
760
761         /// <summary>
762         /// Scrolled will be triggered when the content has been scrolled.
763         /// </summary>
764         public event EventHandler Scrolled
765         {
766             add => _scroller.Scrolled += value;
767             remove => _scroller.Scrolled -= value;
768         }
769
770         /// <summary>
771         /// DragStart will be triggered when dragging the contents around has started.
772         /// </summary>
773         public event EventHandler DragStart
774         {
775             add => _scroller.DragStart += value;
776             remove => _scroller.DragStart -= value;
777         }
778
779         /// <summary>
780         /// DragStop will be triggered when dragging the contents around has stopped.
781         /// </summary>
782         public event EventHandler DragStop
783         {
784             add => _scroller.DragStop += value;
785             remove => _scroller.DragStop -= value;
786         }
787
788         /// <summary>
789         /// PageScrolled will be triggered when the visible page has changed.
790         /// </summary>
791         public event EventHandler PageScrolled
792         {
793             add => _scroller.PageScrolled += value;
794             remove => _scroller.PageScrolled -= value;
795         }
796
797         /// <summary>
798         /// Gets the current region in the content object that is visible through the Scroller.
799         /// </summary>
800         public Rect CurrentRegion => _scroller.CurrentRegion;
801
802         /// <summary>
803         /// Sets or gets the value of HorizontalScrollBarVisiblePolicy
804         /// </summary>
805         /// <remarks>
806         /// ScrollBarVisiblePolicy.Auto means the horizontal scrollbar is made visible if it is needed, and otherwise kept hidden.
807         /// ScrollBarVisiblePolicy.Visible turns it on all the time, and ScrollBarVisiblePolicy.Invisible always keeps it off.
808         /// </remarks>
809         public virtual ScrollBarVisiblePolicy HorizontalScrollBarVisiblePolicy
810         {
811             get => _scroller.HorizontalScrollBarVisiblePolicy;
812             set => _scroller.HorizontalScrollBarVisiblePolicy = value;
813         }
814
815         /// <summary>
816         /// Sets or gets the value of VerticalScrollBarVisiblePolicy
817         /// </summary>
818         /// <remarks>
819         /// ScrollBarVisiblePolicy.Auto means the vertical scrollbar is made visible if it is needed, and otherwise kept hidden.
820         /// ScrollBarVisiblePolicy.Visible turns it on all the time, and ScrollBarVisiblePolicy.Invisible always keeps it off.
821         /// </remarks>
822         public virtual ScrollBarVisiblePolicy VerticalScrollBarVisiblePolicy
823         {
824             get => _scroller.VerticalScrollBarVisiblePolicy;
825             set => _scroller.VerticalScrollBarVisiblePolicy = value;
826         }
827
828         /// <summary>
829         /// Sets or gets the value of ScrollBlock.
830         /// </summary>
831         /// <remarks>
832         /// This function will block scrolling movement  in a given direction.One can disable movements in the X axis, the Y axis or both.
833         /// The default value is ScrollBlock.None, where movements are allowed in both directions.
834         /// </remarks>
835         public ScrollBlock ScrollBlock
836         {
837             get => _scroller.ScrollBlock;
838             set => _scroller.ScrollBlock = value;
839         }
840
841         /// <summary>
842         /// Sets or gets scroll current page number.
843         /// </summary>
844         /// <remarks>
845         /// Current page means the page which meets the top of the viewport.
846         /// If there are two or more pages in the viewport, it returns the number of the page which meets the top of the viewport.
847         /// The page number starts from 0. 0 is the first page.
848         /// </remarks>
849         public int VerticalPageIndex => _scroller.VerticalPageIndex;
850
851         /// <summary>
852         /// Sets or gets scroll current page number.
853         /// </summary>
854         /// <remarks>
855         /// Current page means the page which meets the left of the viewport.
856         /// If there are two or more pages in the viewport, it returns the number of the page which meets the left of the viewport.
857         /// The page number starts from 0. 0 is the first page.
858         /// </remarks>
859         public int HorizontalPageIndex => _scroller.HorizontalPageIndex;
860
861         /// <summary>
862         /// Sets or gets the maximum limit of the movable page at vertical direction.
863         /// </summary>
864         public int VerticalPageScrollLimit
865         {
866             get => _scroller.VerticalPageScrollLimit;
867             set => _scroller.VerticalPageScrollLimit = value;
868         }
869
870         /// <summary>
871         /// Sets or gets the maximum limit of the movable page at horizontal direction.
872         /// </summary>
873         public int HorizontalPageScrollLimit
874         {
875             get => _scroller.HorizontalPageScrollLimit;
876             set => _scroller.HorizontalPageScrollLimit = value;
877         }
878
879         /// <summary>
880         /// Sets or gets the vertical bounce behaviour.
881         /// When scrolling, the scroller may "bounce" when reaching an edge of the content object.
882         /// This is a visual way to indicate the end has been reached.
883         /// This is enabled by default for both axis.
884         /// This API will set if it is enabled for the given axis with the boolean parameters for each axis.
885         /// </summary>
886         public bool VerticalBounce
887         {
888             get => _scroller.VerticalBounce;
889             set => _scroller.VerticalBounce = value;
890         }
891
892         /// <summary>
893         /// Sets or gets the horizontal bounce behaviour.
894         /// When scrolling, the scroller may "bounce" when reaching an edge of the content object.
895         /// This is a visual way to indicate the end has been reached.
896         /// This is enabled by default for both axis.
897         /// This API will set if it is enabled for the given axis with the boolean parameters for each axis.
898         /// </summary>
899         public bool HorizontalBounce
900         {
901             get => _scroller.HorizontalBounce;
902             set => _scroller.HorizontalBounce = value;
903         }
904
905         /// <summary>
906         /// Gets the width of the content object of the scroller.
907         /// </summary>
908         public int ChildWidth
909         {
910             get => _scroller.ChildWidth;
911         }
912
913         /// <summary>
914         /// Gets the height of the content object of the scroller.
915         /// </summary>
916         public int ChildHeight
917         {
918             get => _scroller.ChildHeight;
919         }
920
921         /// <summary>
922         /// Set scrolling gravity values for a scroller.
923         /// The gravity, defines how the scroller will adjust its view when the size of the scroller contents increase.
924         /// The scroller will adjust the view to glue itself as follows.
925         /// x=0.0, for staying where it is relative to the left edge of the content x=1.0, for staying where it is relative to the rigth edge of the content y=0.0, for staying where it is relative to the top edge of the content y=1.0, for staying where it is relative to the bottom edge of the content
926         /// Default values for x and y are 0.0
927         /// </summary>
928         public double HorizontalGravity
929         {
930             get => _scroller.HorizontalGravity;
931             set => _scroller.HorizontalGravity = value;
932         }
933
934         /// <summary>
935         /// Set scrolling gravity values for a scroller.
936         /// The gravity, defines how the scroller will adjust its view when the size of the scroller contents increase.
937         /// The scroller will adjust the view to glue itself as follows.
938         /// x=0.0, for staying where it is relative to the left edge of the content x=1.0, for staying where it is relative to the rigth edge of the content y=0.0, for staying where it is relative to the top edge of the content y=1.0, for staying where it is relative to the bottom edge of the content
939         /// Default values for x and y are 0.0
940         /// </summary>
941         public double VerticalGravity
942         {
943             get => _scroller.VerticalGravity;
944             set => _scroller.VerticalGravity = value;
945         }
946
947         /// <summary>
948         /// Get scroll last page number.
949         /// The page number starts from 0. 0 is the first page. This returns the last page number among the pages.
950         /// </summary>
951         public int LastVerticalPageNumber => _scroller.LastVerticalPageNumber;
952
953         /// <summary>
954         /// Get scroll last page number.
955         /// The page number starts from 0. 0 is the first page. This returns the last page number among the pages.
956         /// </summary>
957         public int LastHorizontalPageNumber => _scroller.LastHorizontalPageNumber;
958
959         /// <summary>
960         /// Set an infinite loop_ for a scroller.
961         /// This function sets the infinite loop vertically.
962         /// If the content is set, it will be shown repeatedly.
963         /// </summary>
964         public bool VerticalLoop
965         {
966             get => _scroller.VerticalLoop;
967             set => _scroller.VerticalLoop = value;
968         }
969
970         /// <summary>
971         /// Set an infinite loop_ for a scroller.
972         /// This function sets the infinite loop horizontally.
973         /// If the content is set, it will be shown repeatedly.
974         /// </summary>
975         public bool HorizontalLoop
976         {
977             get => _scroller.HorizontalLoop;
978             set => _scroller.HorizontalLoop = value;
979         }
980
981         /// <summary>
982         /// Gets or sets the page size to an absolute fixed value, with 0 turning it off for that axis.
983         /// </summary>
984         public int HorizontalPageSize
985         {
986             get => _scroller.HorizontalPageSize;
987             set => _scroller.HorizontalPageSize = value;
988         }
989
990         /// <summary>
991         /// Gets or sets the page size to an absolute fixed value, with 0 turning it off for that axis.
992         /// </summary>
993         public int VerticalPageSize
994         {
995             get => _scroller.VerticalPageSize;
996             set => _scroller.VerticalPageSize = value;
997         }
998
999         /// <summary>
1000         /// Gets or sets a given scroller widget's scrolling page size, relative to its viewport size.
1001         /// </summary>
1002         public double VerticalRelativePageSize
1003         {
1004             get => _scroller.VerticalRelativePageSize;
1005             set => _scroller.VerticalRelativePageSize = value;
1006         }
1007
1008         /// <summary>
1009         /// Gets or sets a given scroller widget's scrolling page size, relative to its viewport size.
1010         /// </summary>
1011         public double HorizontalRelativePageSize
1012         {
1013             get => _scroller.HorizontalRelativePageSize;
1014             set => _scroller.HorizontalRelativePageSize = value;
1015         }
1016
1017         /// <summary>
1018         /// Gets or Sets the page snapping behavior of a scroller.
1019         /// </summary>
1020         /// <remarks>
1021         /// When scrolling, if a scroller is paged (see VerticalRelativePageSize),
1022         /// the scroller may snap to pages when being scrolled, i.e., even if it had momentum to scroll further,
1023         /// it will stop at the next page boundaries. This is disabled, by default, for both axis.
1024         /// This function will set if it that is enabled or not, for each axis.
1025         /// </remarks>
1026         public bool VerticalSnap
1027         {
1028             get => _scroller.VerticalSnap;
1029             set => _scroller.VerticalSnap = value;
1030         }
1031
1032         /// <summary>
1033         /// Gets or Sets the page snapping behavior of a scroller.
1034         /// </summary>
1035         /// <remarks>
1036         /// When scrolling, if a scroller is paged (see HorizontalRelativePageSize),
1037         /// the scroller may snap to pages when being scrolled, i.e., even if it had momentum to scroll further,
1038         /// it will stop at the next page boundaries. This is disabled, by default, for both axis.
1039         /// This function will set if it that is enabled or not, for each axis.
1040         /// </remarks>
1041         public bool HorizontalSnap
1042         {
1043             get => _scroller.HorizontalSnap;
1044             set => _scroller.HorizontalSnap = value;
1045         }
1046
1047         /// <summary>
1048         /// Gets or sets the page size to an absolute fixed value, with 0 turning it off for that axis.
1049         /// </summary>
1050         public int PageHeight
1051         {
1052             get => _scroller.PageHeight;
1053             set => _scroller.PageHeight = value;
1054         }
1055
1056         /// <summary>
1057         /// Gets or sets the page size to an absolute fixed value, with 0 turning it off for that axis.
1058         /// </summary>
1059         public int PageWidth
1060         {
1061             get => _scroller.PageWidth;
1062             set => _scroller.PageWidth = value;
1063         }
1064
1065         /// <summary>
1066         /// Gets or sets the step size to move scroller by key event.
1067         /// </summary>
1068         public int HorizontalStepSize
1069         {
1070             get => _scroller.HorizontalStepSize;
1071             set => _scroller.HorizontalStepSize = value;
1072         }
1073
1074         /// <summary>
1075         /// Gets or sets the step size to move scroller by key event.
1076         /// </summary>
1077         public int VerticalStepSize
1078         {
1079             get => _scroller.VerticalStepSize;
1080             set => _scroller.VerticalStepSize = value;
1081         }
1082
1083         /// <summary>
1084         /// Gets or sets a value whether mouse wheel is enabled or not over the scroller.
1085         /// </summary>
1086         public bool WheelDisabled
1087         {
1088             get => _scroller.WheelDisabled;
1089             set => _scroller.WheelDisabled = value;
1090         }
1091
1092         /// <summary>
1093         /// Gets or sets the type of single direction scroll.
1094         /// </summary>
1095         public ScrollSingleDirection SingleDirection
1096         {
1097             get => _scroller.SingleDirection;
1098             set => _scroller.SingleDirection = value;
1099         }
1100
1101         /// <summary>
1102         /// Sets the scroller minimum size limited to the minimum size of the content.
1103         /// By default the scroller will be as small as its design allows, irrespective of its content.
1104         /// This will make the scroller minimum size the right size horizontally and/or vertically to perfectly fit its content in that direction.
1105         /// </summary>
1106         /// <param name="horizontal">Enable limiting minimum size horizontally</param>
1107         /// <param name="vertical">Enable limiting minimum size vertically</param>
1108         public void MinimumLimit(bool horizontal, bool vertical)
1109         {
1110             _scroller.MinimumLimit(horizontal, vertical);
1111         }
1112
1113         /// <summary>
1114         /// Shows a specific virtual region within the scroller content object by the page number.
1115         /// (0, 0) of the indicated page is located at the top-left corner of the viewport.
1116         /// </summary>
1117         /// <param name="horizontalPageIndex">The horizontal page number.</param>
1118         /// <param name="verticalPageIndex">The vertical page number.</param>
1119         /// <param name="animated">True means slider with animation.</param>
1120         public void ScrollTo(int horizontalPageIndex, int verticalPageIndex, bool animated)
1121         {
1122             _scroller.ScrollTo(horizontalPageIndex, verticalPageIndex, animated);
1123         }
1124
1125         /// <summary>
1126         /// Shows a specific virtual region within the scroller content object.
1127         /// </summary>
1128         /// <remarks>
1129         /// This ensures that all (or part, if it does not fit) of the designated region in the virtual content object ((0, 0)
1130         /// starting at the top-left of the virtual content object) is shown within the scroller.
1131         /// If set "animated" to true, it will allows the scroller to "smoothly slide" to this location
1132         /// (if configuration in general calls for transitions).
1133         /// It may not jump immediately to the new location and may take a while and show other content along the way.
1134         /// </remarks>
1135         /// <param name="region">Rect struct of region.</param>
1136         /// <param name="animated">True means allows the scroller to "smoothly slide" to this location.</param>
1137         public void ScrollTo(Rect region, bool animated)
1138         {
1139             _scroller.ScrollTo(region, animated);
1140         }
1141
1142         #endregion
1143
1144         void InitializeSmartEvent()
1145         {
1146             _selected = new SmartEvent<GenListItemEventArgs>(this, this.RealHandle, "selected", GenListItemEventArgs.CreateFromSmartEvent);
1147             _unselected = new SmartEvent<GenListItemEventArgs>(this, this.RealHandle, "unselected", GenListItemEventArgs.CreateFromSmartEvent);
1148             _activated = new SmartEvent<GenListItemEventArgs>(this, this.RealHandle, "activated", GenListItemEventArgs.CreateFromSmartEvent);
1149             _pressed = new SmartEvent<GenListItemEventArgs>(this, this.RealHandle, "pressed", GenListItemEventArgs.CreateFromSmartEvent);
1150             _released = new SmartEvent<GenListItemEventArgs>(this, this.RealHandle, "released", GenListItemEventArgs.CreateFromSmartEvent);
1151             _doubleClicked = new SmartEvent<GenListItemEventArgs>(this, this.RealHandle, "clicked,double", GenListItemEventArgs.CreateFromSmartEvent);
1152             _expanded = new SmartEvent<GenListItemEventArgs>(this, this.RealHandle, "expanded", GenListItemEventArgs.CreateFromSmartEvent);
1153             _realized = new SmartEvent<GenListItemEventArgs>(this, this.RealHandle, "realized", GenListItemEventArgs.CreateFromSmartEvent);
1154             _unrealized = new SmartEvent<GenListItemEventArgs>(this, this.RealHandle, "unrealized", GenListItemEventArgs.CreateFromSmartEvent);
1155             _longpressed = new SmartEvent<GenListItemEventArgs>(this, this.RealHandle, "longpressed", GenListItemEventArgs.CreateFromSmartEvent);
1156             _moved = new SmartEvent<GenListItemEventArgs>(this, this.RealHandle, "moved", GenListItemEventArgs.CreateFromSmartEvent);
1157             _movedAfter = new SmartEvent<GenListItemEventArgs>(this, this.RealHandle, "moved,after", GenListItemEventArgs.CreateFromSmartEvent);
1158             _movedBefore = new SmartEvent<GenListItemEventArgs>(this, this.RealHandle, "moved,before", GenListItemEventArgs.CreateFromSmartEvent);
1159             _scrollAnimationStarted = new SmartEvent(this, this.RealHandle, "scroll,anim,start");
1160             _scrollAnimationStopped = new SmartEvent(this, this.RealHandle, "scroll,anim,stop");
1161             _changed = new SmartEvent(this, this.RealHandle, "changed");
1162
1163             _selected.On += (s, e) => { if (e.Item != null) ItemSelected?.Invoke(this, e); };
1164             _unselected.On += (s, e) => { if (e.Item != null) ItemUnselected?.Invoke(this, e); };
1165             _activated.On += (s, e) => { if (e.Item != null) ItemActivated?.Invoke(this, e); };
1166             _pressed.On += (s, e) => { if (e.Item != null) ItemPressed?.Invoke(this, e); };
1167             _released.On += (s, e) => { if (e.Item != null) ItemReleased?.Invoke(this, e); };
1168             _doubleClicked.On += (s, e) => { if (e.Item != null) ItemDoubleClicked?.Invoke(this, e); };
1169             _expanded.On += (s, e) => { if (e.Item != null) ItemExpanded?.Invoke(this, e); };
1170             _realized.On += (s, e) => { if (e.Item != null) ItemRealized?.Invoke(this, e); };
1171             _unrealized.On += (s, e) => { if (e.Item != null) ItemUnrealized?.Invoke(this, e); };
1172             _longpressed.On += (s, e) => { if (e.Item != null) ItemLongPressed?.Invoke(this, e); };
1173             _moved.On += (s, e) => { if (e.Item != null) ItemMoved?.Invoke(this, e); };
1174             _movedAfter.On += (s, e) => { if (e.Item != null) ItemMovedAfter?.Invoke(this, e); };
1175             _movedBefore.On += (s, e) => { if (e.Item != null) ItemMovedBefore?.Invoke(this, e); };
1176         }
1177
1178         void AddInternal(GenListItem item)
1179         {
1180             _children.Add(item);
1181             item.Deleted += Item_Deleted;
1182         }
1183
1184         void Item_Deleted(object sender, EventArgs e)
1185         {
1186             _children.Remove((GenListItem)sender);
1187         }
1188     }
1189 }