svn update: 49550 (latest:49550)
[framework/uifw/elementary.git] / src / lib / elm_genlist.c
1 /*
2  *
3  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
4  */
5 #include <Elementary.h>
6 #include "elm_priv.h"
7
8 /**
9  * @defgroup Genlist Genlist
10  *
11  * The aim was to have  more expansive list that the simple list in
12  * Elementary that could have more flexible items and allow many more entries
13  * while still being fast and low on memory usage. At the same time it was
14  * also made to be able to do tree structures. But the price to pay is more
15  * complexity when it comes to usage. If all you want is a simple list with
16  * icons and a single label, use the normal List object.
17  *
18  * Signals that you can add callbacks for are:
19  *
20  * clicked - This is called when a user has double-clicked an item. The
21  * event_info parameter is the genlist item that was double-clicked.
22  *
23  * selected - This is called when a user has made an item selected. The
24  * event_info parameter is the genlist item that was selected.
25  *
26  * unselected - This is called when a user has made an item unselected. The
27  * event_info parameter is the genlist item that was unselected.
28  *
29  * expanded -  This is called when elm_genlist_item_expanded_set() is called
30  * and the item is now meant to be expanded. The event_info parameter is the
31  * genlist item that was indicated to expand. It is the job of this callback
32  * to then fill in the child items.
33  *
34  * contracted - This is called when elm_genlist_item_expanded_set() is called
35  * and the item is now meant to be contracted. The event_info parameter is
36  * the genlist item that was indicated to contract. It is the job of this
37  * callback to then delete the child items
38  *
39  * expand,request - This is called when a user has indicated they want to
40  * expand a tree branch item. The callback should decide if the item can
41  * expand (has any children) and then call elm_genlist_item_expanded_set()
42  * appropriately to set the state. The event_info parameter is the genlist
43  * item that was indicated to expand.
44  *
45  * contract,request - This is called when a user has indicated they want to
46  * contract a tree branch item. The callback should decide if the item can
47  * contract (has any children) and then call elm_genlist_item_expanded_set()
48  * appropriately to set the state. The event_info parameter is the genlist
49  * item that was indicated to contract.
50  *
51  * realized - This is called when the item in the list is created as a real
52  * evas object. event_info parameter is the genlist item that was created.
53  * The object may be deleted at any time, so it is up to the caller to
54  * not use the object pointer from elm_genlist_item_object_get() in a way
55  * where it may point to freed objects.
56  *
57  * drag,start,up - This is called when the item in the list has been dragged
58  * (not scrolled) up.
59  *
60  * drag,start,down - This is called when the item in the list has been dragged
61  * (not scrolled) down.
62  *
63  * drag,start,left - This is called when the item in the list has been dragged
64  * (not scrolled) left.
65  *
66  * drag,start,right - This is called when the item in the list has been dragged
67  * (not scrolled) right.
68  *
69  * drag,stop - This is called when the item in the list has stopped being
70  * dragged.
71  *
72  * drag - This is called when the item in the list is being dragged.
73  *
74  * Genlist has a fairly large API, mostly because it's relatively complex,
75  * trying to be both expansive, powerful and efficient. First we will begin
76  * an overview o the theory behind genlist.
77  *
78  * Evas tracks every object you create. Every time it processes an event
79  * (mouse move, down, up etc.) it needs to walk through objects and find out
80  * what event that affects. Even worse every time it renders display updates,
81  * in order to just calculate what to re-draw, it needs to walk through many
82  * many many objects. Thus, the more objects you keep active, the more
83  * overhead Evas has in just doing its work. It is advisable to keep your
84  * active objects to the minimum working set you need. Also remember that
85  * object creation and deletion carries an overhead, so there is a
86  * middle-ground, which is not easily determined. But don't keep massive lists
87  * of objects you can't see or use. Genlist does this with list objects. It
88  * creates and destroys them dynamically as you scroll around. It groups them
89  * into blocks so it can determine the visibility etc. of a whole block at
90  * once as opposed to having to walk the whole list. This 2-level list allows
91  * for very large numbers of items to be in the list (tests have used up to
92  * 2,000,000 items). Also genlist employs a queue for adding items. As items
93  * may be different sizes, every item added needs to be calculated as to its
94  * size and thus this presents a lot of overhead on populating the list, this
95  * genlist employs a queue. Any item added is queued and spooled off over
96  * time, actually appearing some time later, so if your list has many members
97  * you may find it takes a while for them to all appear, with your process
98  * consuming a lot of CPU while it is busy spooling.
99  *
100  * Genlist also implements a tree structure, but it does so with callbacks to
101  * the application, with the application filling in tree structures when
102  * requested (allowing for efficient building of a very deep tree that could
103  * even be used for file-management). See the above smart signal callbacks for
104  * details.
105  *
106  * An item in the genlist world can have 0 or more text labels (they can be
107  * regular text or textblock – that's up to the style to determine), 0 or
108  * more icons (which are simply objects swallowed into the genlist item) and
109  * 0 or more boolean states that can be used for check, radio or other
110  * indicators by the edje theme style. An item may be one of several styles
111  * (Elementary provides 2 by default - “default” and “double_label”, but this
112  * can be extended by system or application custom themes/overlays/extensions).
113  *
114  * In order to implement the ability to add and delete items on the fly,
115  * Genlist implements a class/callback system where the application provides
116  * a structure with information about that type of item (genlist may contain
117  * multiple different items with different classes, states and styles).
118  * Genlist will call the functions in this struct (methods) when an item is
119  * “realized” (that is created dynamically while scrolling). All objects will
120  * simply be deleted  when no longer needed with evas_object_del(). The
121  * Elm_Genlist_Item_Class structure contains the following members:
122  *
123  * item_style - This is a constant string and simply defines the name of the
124  * item style. It must be specified and the default should be “default”.
125  *
126  * func.label_get - This function is called when an actual item object is
127  * created. The data parameter is the data parameter passed to
128  * elm_genlist_item_append() and related item creation functions. The obj
129  * parameter is the genlist object and the part parameter is the string name
130  * of the text part in the edje design that is listed as one of the possible
131  * labels that can be set. This function must return a strudup()'ed string as
132  * the caller will free() it when done.
133  *
134  * func.icon_get - This function is called when an actual item object is
135  * created. The data parameter is the data parameter passed to
136  * elm_genlist_item_append() and related item creation functions. The obj
137  * parameter is the genlist object and the part parameter is the string name
138  * of the icon part in the edje design that is listed as one of the possible
139  * icons that can be set. This must return NULL for no object or a valid
140  * object. The object will be deleted by genlist on shutdown or when the item
141  * its unrealized.
142  *
143  * func.state_get - This function is called when an actual item object is
144  * created. The data parameter is the data parameter passed to
145  * elm_genlist_item_append() and related item creation functions. The obj
146  * parameter is the genlist object and the part parameter is the string name
147  * of the state part in the edje design that is listed as one of the possible
148  * states that can be set. Return 0 for false or 1 for true. Genlist will
149  * emit a signal to the edje object with “elm,state,XXX,active” “elm” when
150  * true (the default is false), where XXX is the name of the part.
151  *
152  * func.del - This is called when elm_genlist_item_del() is called on an
153  * item, elm_genlist_clear() is called on the genlist, or
154  * elm_genlist_item_subitems_clear() is called to clear sub-items. This is
155  * intended for use when actual genlist items are deleted, so any backing
156  * data attached to the item (e.g. its data parameter on creation) can be
157  * deleted.
158  *
159  * Items can be added by several calls. All of them return a Elm_Genlist_Item
160  * handle that is an internal member inside the genlist. They all take a data
161  * parameter that is meant to be used for a handle to the applications
162  * internal data (eg the struct with the original item data). The parent
163  * parameter is the parent genlist item this belongs to if it is a tree, and
164  * NULL if there is no parent. The flags can be a bitmask of
165  * ELM_GENLIST_ITEM_NONE and ELM_GENLIST_ITEM_SUBITEMS. If
166  * ELM_GENLIST_ITEM_SUBITEMS is set then this item is displayed as a item
167  * that is able to expand and have child items. The func parameter is a
168  * convenience callback that is called when the item is selected and the data
169  * parameter will be the func_data parameter, obj be the genlist object and
170  * vent_info will be the genlist item.
171  *
172  * elm_genlist_item_append() appends an item to the end of the list, or if
173  * there is a parent, to the end of all the child items of the parent.
174  * elm_genlist_item_prepend() is the same but prepends to the beginning of
175  * the list or children list. elm_genlist_item_insert_before() inserts at
176  * item before another item and elm_genlist_item_insert_after() inserts after
177  * the indicated item.
178  *
179  * The application can clear the list with elm_genlist_clear() which deletes
180  * all the items in the list and elm_genlist_item_del() will delete a specific
181  * item. elm_genlist_item_subitems_clear() will clear all items that are
182  * children of the indicated parent item.
183  *
184  * If the application wants multiple items to be able to be selected,
185  * elm_genlist_multi_select_set() can enable this. If the list is
186  * single-selection only (the default), then elm_genlist_selected_item_get()
187  * will return the selected item, if any, or NULL I none is selected. If the
188  * list is multi-select then elm_genlist_selected_items_get() will return a
189  * list (that is only valid as long as no items are modified (added, deleted,
190  * selected or unselected).
191  *
192  * To help inspect list items you can jump to the item at the top of the list
193  * with elm_genlist_first_item_get() which will return the item pointer, and
194  * similarly elm_genlist_last_item_get() gets the item at the end of the list.
195  * elm_genlist_item_next_get() and elm_genlist_item_prev_get() get the next
196  * and previous items respectively relative to the indicated item. Using
197  * these calls you can walk the entire item list/tree. Note that as a tree
198  * the items are flattened in the list, so elm_genlist_item_parent_get() will
199  * let you know which item is the parent (and thus know how to skip them if
200  * wanted).
201  *
202  * There are also convenience functions. elm_genlist_item_genlist_get() will
203  * return the genlist object the item belongs to.  elm_genlist_item_show()
204  * will make the scroller scroll to show that specific item so its visible.
205  * elm_genlist_item_data_get() returns the data pointer set by the item
206  * creation functions.
207  *
208  * If an item changes (state of boolean changes, label or icons change),
209  * then use elm_genlist_item_update() to have genlist update the item with
210  * the new state. Genlist will re-realize the item thus call the functions
211  * in the _Elm_Genlist_Item_Class for that item.
212  *
213  * To programmatically (un)select an item use elm_genlist_item_selected_set().
214  * To get its selected state use elm_genlist_item_selected_get(). Similarly
215  * to expand/contract and item and get its expanded state, use
216  * elm_genlist_item_expanded_set() and elm_genlist_item_expanded_get(). And
217  * again to make an item disabled (unable to be selected and appear
218  * differently) use elm_genlist_item_disabled_set() to set this and
219  * elm_genlist_item_disabled_get() to get the disabled state.
220  *
221  * In general to indicate how the genlist should expand items horizontally to
222  * fill the list area, use elm_genlist_horizontal_mode_set(). Valid modes are
223  * ELM_LIST_LIMIT and ELM_LIST_SCROLL . The default is ELM_LIST_SCROLL. This
224  * mode means that if items are too wide to fit, the scroller will scroll
225  * horizontally. Otherwise items are expanded to fill the width of the
226  * viewport of the scroller. If it is ELM_LIST_LIMIT, Items will be expanded
227  * to the viewport width and limited to that size. This can be combined with
228  * a different style that uses edjes' ellipsis feature (cutting text off like
229  * this: “tex...”).
230  *
231  * Items will only call their selection func and callback when first becoming
232  * selected. Any further clicks will do nothing, unless you enable always
233  * select with elm_genlist_always_select_mode_set(). This means even if
234  * selected, every click will make the selected callbacks be called.
235  * elm_genlist_no_select_mode_set() will turn off the ability to select
236  * items entirely and they will neither appear selected nor call selected
237  * callback functions.
238  *
239  * Remember that you can create new styles and add you own theme augmentation
240  * per application with elm_theme_extension_add(). If you absolutely must
241  * have a specific style that overrides any theme the user or system sets up
242  * you can use elm_theme_overlay_add() to add such a file.
243  */
244
245 typedef struct _Widget_Data Widget_Data;
246 typedef struct _Item_Block Item_Block;
247 typedef struct _Pan Pan;
248
249 struct _Widget_Data
250 {
251    Evas_Object *obj, *scr, *pan_smart;
252    Eina_Inlist *items, *blocks;
253    Pan *pan;
254    Evas_Coord pan_x, pan_y, minw, minh;
255    Ecore_Job *calc_job, *update_job;
256    Ecore_Idler *queue_idler;
257    Eina_List *queue, *selected;
258    Elm_Genlist_Item *show_item;
259    Elm_List_Mode mode;
260    Eina_Bool on_hold : 1;
261    Eina_Bool multi : 1;
262    Eina_Bool always_select : 1;
263    Eina_Bool longpressed : 1;
264    Eina_Bool wasselected : 1;
265    Eina_Bool no_select : 1;
266    Eina_Bool bring_in : 1;
267    Eina_Bool compress : 1;
268    Eina_Bool homogeneous : 1;
269    int item_width;
270    int item_height;
271    int max_items_per_block;
272 };
273
274 struct _Item_Block
275 {
276    EINA_INLIST;
277    int count;
278    int num;
279    Widget_Data *wd;
280    Eina_List *items;
281    Evas_Coord x, y, w, h, minw, minh;
282    Eina_Bool want_unrealize : 1;
283    Eina_Bool realized : 1;
284    Eina_Bool changed : 1;
285    Eina_Bool updateme : 1;
286    Eina_Bool showme : 1;
287 };
288
289 struct _Elm_Genlist_Item
290 {
291    EINA_INLIST;
292    Widget_Data *wd;
293    Item_Block *block;
294    Eina_List *items;
295    Evas_Coord x, y, w, h, minw, minh;
296    const Elm_Genlist_Item_Class *itc;
297    const void *data;
298    Elm_Genlist_Item *parent;
299    Elm_Genlist_Item_Flags flags;
300    struct 
301      {
302         Evas_Smart_Cb func;
303         const void *data;
304      } func;
305
306    Evas_Object *base, *spacer;
307    Eina_List *labels, *icons, *states, *icon_objs;
308    Ecore_Timer *long_timer;
309    Evas_Coord dx, dy;
310
311    Elm_Genlist_Item *rel;
312    int relcount;
313    int walking;
314    Eina_Bool before : 1;
315
316    Eina_Bool want_unrealize : 1;
317    Eina_Bool realized : 1;
318    Eina_Bool selected : 1;
319    Eina_Bool hilighted : 1;
320    Eina_Bool expanded : 1;
321    Eina_Bool disabled : 1;
322    Eina_Bool display_only : 1;
323    Eina_Bool mincalcd : 1;
324    Eina_Bool queued : 1;
325    Eina_Bool showme : 1;
326    Eina_Bool delete_me : 1;
327    Eina_Bool down : 1;
328    Eina_Bool dragging : 1;
329    Eina_Bool updateme : 1;
330 };
331
332 struct _Pan
333 {
334    Evas_Object_Smart_Clipped_Data __clipped_data;
335    Widget_Data *wd;
336 };
337
338 static const char *widtype = NULL;
339 static void _del_hook(Evas_Object *obj);
340 static void _theme_hook(Evas_Object *obj);
341 //static void _show_region_hook(void *data, Evas_Object *obj);
342 static void _sizing_eval(Evas_Object *obj);
343 static void _item_unrealize(Elm_Genlist_Item *it);
344 static void _item_block_unrealize(Item_Block *itb);
345 static void _calc_job(void *data);
346
347 static Evas_Smart_Class _pan_sc = EVAS_SMART_CLASS_INIT_VERSION;
348
349 static void
350 _del_hook(Evas_Object *obj)
351 {
352    Widget_Data *wd = elm_widget_data_get(obj);
353    if (!wd) return;
354    if (wd->calc_job) ecore_job_del(wd->calc_job);
355    if (wd->update_job) ecore_job_del(wd->update_job);
356    free(wd);
357 }
358
359 static void
360 _del_pre_hook(Evas_Object *obj)
361 {
362    Widget_Data *wd = elm_widget_data_get(obj);
363    if (!wd) return;
364    evas_object_del(wd->pan_smart);
365    wd->pan_smart = NULL;
366    elm_genlist_clear(obj);
367 }
368
369 static void
370 _theme_hook(Evas_Object *obj)
371 {
372    Widget_Data *wd = elm_widget_data_get(obj);
373    Item_Block *itb;
374    if (!wd) return;
375    elm_smart_scroller_object_theme_set(obj, wd->scr, "genlist", "base", elm_widget_style_get(obj));
376 //   edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
377    EINA_INLIST_FOREACH(wd->blocks, itb)
378      {
379         Eina_List *l;
380         Elm_Genlist_Item *it;
381         
382         if (itb->realized) _item_block_unrealize(itb);
383         EINA_LIST_FOREACH(itb->items, l, it)
384           it->mincalcd = EINA_FALSE;
385
386         itb->changed = EINA_TRUE;
387      }
388    if (wd->calc_job) ecore_job_del(wd->calc_job);
389    wd->calc_job = ecore_job_add(_calc_job, wd);
390    _sizing_eval(obj);
391 }
392
393 /*
394 static void
395 _show_region_hook(void *data, Evas_Object *obj)
396 {
397    Widget_Data *wd = elm_widget_data_get(data);
398    Evas_Coord x, y, w, h;
399    if (!wd) return;
400    elm_widget_show_region_get(obj, &x, &y, &w, &h);
401    elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
402 }
403 */
404
405 static void
406 _sizing_eval(Evas_Object *obj)
407 {
408    Widget_Data *wd = elm_widget_data_get(obj);
409    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
410    if (!wd) return;
411    evas_object_size_hint_min_get(wd->scr, &minw, &minh);
412    evas_object_size_hint_max_get(wd->scr, &maxw, &maxh);
413    minh = -1;
414    if (wd->mode != ELM_LIST_LIMIT) minw = -1;
415    else
416      {
417         Evas_Coord  vmw, vmh, vw, vh;
418         
419         minw = wd->minw;
420         maxw = -1;
421         elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
422         if ((minw > 0) && (vw < minw)) vw = minw;
423         else if ((maxw > 0) && (vw > maxw)) vw = maxw;
424         minw = -1;
425         edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), &vmw, &vmh);
426         minw = vmw + minw;
427      }
428    evas_object_size_hint_min_set(obj, minw, minh);
429    evas_object_size_hint_max_set(obj, maxw, maxh);
430 }
431
432 static void
433 _item_hilight(Elm_Genlist_Item *it)
434 {
435    const char *selectraise;
436    if ((it->wd->no_select) || (it->delete_me) || (it->hilighted)) return;
437    edje_object_signal_emit(it->base, "elm,state,selected", "elm");
438    selectraise = edje_object_data_get(it->base, "selectraise");
439    if ((selectraise) && (!strcmp(selectraise, "on")))
440      evas_object_raise(it->base);
441    it->hilighted = EINA_TRUE;
442 }
443
444 static void
445 _item_block_del(Elm_Genlist_Item *it)
446 {
447    Eina_Inlist *il;
448    Item_Block *itb = it->block;
449
450    itb->items = eina_list_remove(itb->items, it);
451    itb->count--;
452    itb->changed = EINA_TRUE;
453    if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
454    it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
455    if (itb->count < 1)
456      {
457         il = EINA_INLIST_GET(itb);
458         Item_Block *itbn = (Item_Block *)(il->next);
459         if (it->parent)
460           it->parent->items = eina_list_remove(it->parent->items, it);
461         else
462           it->wd->blocks = eina_inlist_remove(it->wd->blocks, il);
463         free(itb);
464         if (itbn) itbn->changed = EINA_TRUE;
465      }
466    else
467      {
468         if (itb->count < 16)
469           {
470              il = EINA_INLIST_GET(itb);
471              Item_Block *itbp = (Item_Block *)(il->prev);
472              Item_Block *itbn = (Item_Block *)(il->next);
473              if ((itbp) && ((itbp->count + itb->count) < 48))
474                {
475                   Elm_Genlist_Item *it2;
476
477                   EINA_LIST_FREE(itb->items, it2)
478                     {
479                        it2->block = itbp;
480                        itbp->items = eina_list_append(itbp->items, it2);
481                        itbp->count++;
482                        itbp->changed = EINA_TRUE;
483                     }
484                   it->wd->blocks = eina_inlist_remove(it->wd->blocks, EINA_INLIST_GET(itb));
485                   free(itb);
486                }
487              else if ((itbn) && ((itbn->count + itb->count) < 48))
488                {
489                   while (itb->items)
490                     {
491                        Eina_List *last = eina_list_last(itb->items);
492                        Elm_Genlist_Item *it2 = last->data;
493
494                        it2->block = itbn;
495                        itb->items = eina_list_remove_list(itb->items, last);
496                        itbn->items = eina_list_prepend(itbn->items, it2);
497                        itbn->count++;
498                        itbn->changed = EINA_TRUE;
499                     }
500                   it->wd->blocks = 
501                     eina_inlist_remove(it->wd->blocks, EINA_INLIST_GET(itb));
502                   free(itb);
503                }
504           }
505      }
506 }
507
508 static void
509 _item_del(Elm_Genlist_Item *it)
510 {
511    elm_genlist_item_subitems_clear(it);
512    if (it->wd->show_item == it) it->wd->show_item = NULL;
513    if (it->selected) it->wd->selected = eina_list_remove(it->wd->selected, it);
514    if (it->realized) _item_unrealize(it);
515    if (it->block) _item_block_del(it);
516    if ((!it->delete_me) && (it->itc->func.del)) 
517      it->itc->func.del(it->data, it->wd->obj);
518    it->delete_me = EINA_TRUE;
519    if (it->queued)
520      it->wd->queue = eina_list_remove(it->wd->queue, it);
521    it->wd->items = eina_inlist_remove(it->wd->items, EINA_INLIST_GET(it));
522    if (it->parent)
523      it->parent->items = eina_list_remove(it->parent->items, it);
524    if (it->long_timer) ecore_timer_del(it->long_timer);
525    free(it);
526 }
527
528 static void
529 _item_select(Elm_Genlist_Item *it)
530 {
531    if ((it->wd->no_select) || (it->delete_me)) return;
532    if (it->selected)
533      {
534         if (it->wd->always_select) goto call;
535         return;
536      }
537    it->selected = EINA_TRUE;
538    it->wd->selected = eina_list_append(it->wd->selected, it);
539    call:
540    it->walking++;
541    if (it->func.func) it->func.func((void *)it->func.data, it->wd->obj, it);
542    if (!it->delete_me)
543      evas_object_smart_callback_call(it->wd->obj, "selected", it);
544    it->walking--;
545    if ((it->walking == 0) && (it->delete_me))
546      {
547         if (it->relcount == 0) _item_del(it);
548      }
549 }
550
551 static void
552 _item_unselect(Elm_Genlist_Item *it)
553 {
554    const char *stacking, *selectraise;
555
556    if ((it->delete_me) || (!it->hilighted)) return;
557    edje_object_signal_emit(it->base, "elm,state,unselected", "elm");
558    stacking = edje_object_data_get(it->base, "stacking");
559    selectraise = edje_object_data_get(it->base, "selectraise");
560    if ((selectraise) && (!strcmp(selectraise, "on")))
561      {
562         if ((stacking) && (!strcmp(stacking, "below")))
563           evas_object_lower(it->base);
564      }
565    it->hilighted = EINA_FALSE;
566    if (it->selected)
567      {
568         it->selected = EINA_FALSE;
569         it->wd->selected = eina_list_remove(it->wd->selected, it);
570         evas_object_smart_callback_call(it->wd->obj, "unselected", it);
571      }
572 }
573
574 static void
575 _mouse_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj, void *event_info)
576 {
577    Elm_Genlist_Item *it = data;
578    Evas_Event_Mouse_Move *ev = event_info;
579    Evas_Coord minw = 0, minh = 0, x, y, dx, dy, adx, ady;
580
581    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
582      {
583         if (!it->wd->on_hold)
584           {
585              it->wd->on_hold = EINA_TRUE;
586              _item_unselect(it);
587           }
588      }
589    if ((it->dragging) && (it->down))
590      {
591         if (it->long_timer)
592           {
593              ecore_timer_del(it->long_timer);
594              it->long_timer = NULL;
595           }
596         evas_object_smart_callback_call(it->wd->obj, "drag", it);
597         return;
598      }
599    if ((!it->down)/* || (it->wd->on_hold)*/ || (it->wd->longpressed))
600      {
601         if (it->long_timer)
602           {
603              ecore_timer_del(it->long_timer);
604              it->long_timer = NULL;
605           }
606         return;
607      }
608    if (!it->display_only)
609      elm_coords_finger_size_adjust(1, &minw, 1, &minh);
610    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
611    x = ev->cur.canvas.x - x;
612    y = ev->cur.canvas.y - y;
613    dx = x - it->dx;
614    adx = dx;
615    if (adx < 0) adx = -dx;
616    dy = y - it->dy;
617    ady = dy;
618    if (ady < 0) ady = -dy;
619    minw /= 2;
620    minh /= 2;
621    if ((adx > minw) || (ady > minh))
622      {
623         it->dragging = 1;
624         if (it->long_timer)
625           {
626              ecore_timer_del(it->long_timer);
627              it->long_timer = NULL;
628           }
629         if (!it->wd->wasselected)
630           _item_unselect(it);
631         it->wd->wasselected = 0;
632         if (dy < 0)
633           {
634              if (ady > adx)
635                evas_object_smart_callback_call(it->wd->obj, "drag,start,up", it);
636              else
637                {
638                   if (dx < 0)
639                     evas_object_smart_callback_call(it->wd->obj, 
640                                                     "drag,start,left", it);
641                   else
642                     evas_object_smart_callback_call(it->wd->obj, 
643                                                     "drag,start,right", it);
644                }
645           }
646         else
647           {
648              if (ady > adx)
649                evas_object_smart_callback_call(it->wd->obj, 
650                                                "drag,start,down", it);
651              else
652                {
653                   if (dx < 0)
654                     evas_object_smart_callback_call(it->wd->obj, 
655                                                     "drag,start,left", it);
656                   else
657                     evas_object_smart_callback_call(it->wd->obj, 
658                                                     "drag,start,right", it);
659                }
660           }
661      }
662 }
663
664 static int
665 _long_press(void *data)
666 {
667    Elm_Genlist_Item *it = data;
668
669    it->long_timer = NULL;
670    if ((it->disabled) || (it->dragging)) return 0;
671    it->wd->longpressed = EINA_TRUE;
672    evas_object_smart_callback_call(it->wd->obj, "longpressed", it);
673    return 0;
674 }
675
676 static void
677 _mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj, void *event_info)
678 {
679    Elm_Genlist_Item *it = data;
680    Evas_Event_Mouse_Down *ev = event_info;
681    Evas_Coord x, y;
682
683    if (ev->button != 1) return;
684    it->down = 1;
685    it->dragging  = 0;
686    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
687    it->dx = ev->canvas.x - x;
688    it->dy = ev->canvas.y - y;
689    it->wd->longpressed = EINA_FALSE;
690    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) it->wd->on_hold = EINA_TRUE;
691    else it->wd->on_hold = EINA_FALSE;
692    it->wd->wasselected = it->selected;
693    _item_hilight(it);
694    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
695      evas_object_smart_callback_call(it->wd->obj, "clicked", it);
696    if (it->long_timer) ecore_timer_del(it->long_timer);
697    if (it->realized)
698      it->long_timer = ecore_timer_add(1.0, _long_press, it);
699    else
700      it->long_timer = NULL;
701 }
702
703 static void
704 _mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
705 {
706    Elm_Genlist_Item *it = data;
707    Evas_Event_Mouse_Up *ev = event_info;
708    Eina_Bool dragged = EINA_FALSE;
709
710    if (ev->button != 1) return;
711    it->down = 0;
712    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) it->wd->on_hold = EINA_TRUE;
713    else it->wd->on_hold = EINA_FALSE;
714    if (it->long_timer)
715      {
716         ecore_timer_del(it->long_timer);
717         it->long_timer = NULL;
718      }
719    if (it->dragging)
720      {
721         it->dragging = 0;
722         evas_object_smart_callback_call(it->wd->obj, "drag,stop", it);
723         dragged = 1;
724      }
725    if (it->wd->on_hold)
726      {
727         it->wd->longpressed = EINA_FALSE;
728         it->wd->on_hold = EINA_FALSE;
729         return;
730      }
731    if (it->wd->longpressed)
732      {
733         it->wd->longpressed = EINA_FALSE;
734         if (!it->wd->wasselected)
735           _item_unselect(it);
736         it->wd->wasselected = 0;
737         return;
738      }
739    if (dragged)
740      {
741         if (it->want_unrealize)
742           {
743              _item_unrealize(it);
744              if (it->block->want_unrealize)
745                _item_block_unrealize(it->block);
746           }
747      }
748    if ((it->disabled) || (dragged)) return;
749    if (it->wd->multi)
750      {
751         if (!it->selected)
752           {
753              _item_hilight(it);
754              _item_select(it);
755           }
756         else _item_unselect(it);
757      }
758    else
759      {
760         if (!it->selected)
761           {
762              Widget_Data *wd = it->wd;
763              if (wd)
764                {
765                   while (wd->selected) _item_unselect(wd->selected->data);
766                }
767           }
768         else
769           {
770              const Eina_List *l, *l_next;
771              Elm_Genlist_Item *it2;
772
773              EINA_LIST_FOREACH_SAFE(it->wd->selected, l, l_next, it2)
774                if (it2 != it) _item_unselect(it2);
775 //           _item_hilight(it);
776 //           _item_select(it);
777           }
778         _item_hilight(it);
779         _item_select(it);
780      }
781 }
782
783 static void
784 _signal_expand_toggle(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
785 {
786    Elm_Genlist_Item *it = data;
787
788    if (it->expanded)
789      evas_object_smart_callback_call(it->wd->obj, "contract,request", it);
790    else
791      evas_object_smart_callback_call(it->wd->obj, "expand,request", it);
792 }
793
794 static void
795 _signal_expand(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
796 {
797    Elm_Genlist_Item *it = data;
798
799    if (!it->expanded)
800      evas_object_smart_callback_call(it->wd->obj, "expand,request", it);
801 }
802
803 static void
804 _signal_contract(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
805 {
806    Elm_Genlist_Item *it = data;
807
808    if (it->expanded)
809      evas_object_smart_callback_call(it->wd->obj, "contract,request", it);
810 }
811
812 static void
813 _item_realize(Elm_Genlist_Item *it, int in, int calc)
814 {
815    Elm_Genlist_Item *it2;
816    const char *stacking;
817    const char *treesize;
818    char buf[1024];
819    int depth, tsize = 20;
820
821    if ((it->realized) || (it->delete_me)) return;
822    it->base = edje_object_add(evas_object_evas_get(it->wd->obj));
823    edje_object_scale_set(it->base, elm_widget_scale_get(it->wd->obj) * 
824                          _elm_config->scale);
825    evas_object_smart_member_add(it->base, it->wd->pan_smart);
826    elm_widget_sub_object_add(it->wd->obj, it->base);
827
828    if (it->flags & ELM_GENLIST_ITEM_SUBITEMS) strncpy(buf, "tree", sizeof(buf));
829    else strncpy(buf, "item", sizeof(buf));
830    if (it->wd->compress) strncat(buf, "_compress", sizeof(buf) - strlen(buf));
831
832    if (in & 0x1) strncat(buf, "_odd", sizeof(buf) - strlen(buf));
833    strncat(buf, "/", sizeof(buf) - strlen(buf));
834    strncat(buf, it->itc->item_style, sizeof(buf) - strlen(buf));
835    
836    _elm_theme_object_set(it->wd->obj, it->base, "genlist", buf, elm_widget_style_get(it->wd->obj));
837    it->spacer = evas_object_rectangle_add(evas_object_evas_get(it->wd->obj));
838    evas_object_color_set(it->spacer, 0, 0, 0, 0);
839    elm_widget_sub_object_add(it->wd->obj, it->spacer);
840    for (it2 = it, depth = 0; it2->parent; it2 = it2->parent) depth += 1;
841    treesize = edje_object_data_get(it->base, "treesize");
842    if (treesize) tsize = atoi(treesize);
843    evas_object_size_hint_min_set(it->spacer,
844                                  (depth * tsize) * _elm_config->scale, 1);
845    edje_object_part_swallow(it->base, "elm.swallow.pad", it->spacer);
846    if (!calc)
847      {
848         edje_object_signal_callback_add(it->base, "elm,action,expand,toggle",
849                                         "elm", _signal_expand_toggle, it);
850         edje_object_signal_callback_add(it->base, "elm,action,expand", "elm",
851                                         _signal_expand, it);
852         edje_object_signal_callback_add(it->base, "elm,action,contract",
853                                         "elm", _signal_contract, it);
854         stacking = edje_object_data_get(it->base, "stacking");
855         if (stacking)
856           {
857              if (!strcmp(stacking, "below")) evas_object_lower(it->base);
858              else if (!strcmp(stacking, "above")) evas_object_raise(it->base);
859           }
860         evas_object_event_callback_add(it->base, EVAS_CALLBACK_MOUSE_DOWN,
861                                        _mouse_down, it);
862         evas_object_event_callback_add(it->base, EVAS_CALLBACK_MOUSE_UP,
863                                        _mouse_up, it);
864         evas_object_event_callback_add(it->base, EVAS_CALLBACK_MOUSE_MOVE,
865                                        _mouse_move, it);
866         if (it->selected)
867           edje_object_signal_emit(it->base, "elm,state,selected", "elm");
868         if (it->disabled)
869           edje_object_signal_emit(it->base, "elm,state,disabled", "elm");
870         if (it->expanded)
871           edje_object_signal_emit(it->base, "elm,state,expanded", "elm");
872      }
873
874    if (calc && it->wd->homogeneous && it->wd->item_width)
875      {
876         /* homogenous genlist shortcut */
877         if (!it->mincalcd)
878           {
879              it->w = it->minw = it->wd->item_width;
880              it->h = it->minh = it->wd->item_height;
881              it->mincalcd = EINA_TRUE;
882           }
883      }
884    else
885      {
886         if (it->itc->func.label_get)
887           {
888              const Eina_List *l;
889              const char *key;
890
891              it->labels = _elm_stringlist_get(edje_object_data_get(it->base, "labels"));
892              EINA_LIST_FOREACH(it->labels, l, key)
893                {
894                   char *s = it->itc->func.label_get(it->data, it->wd->obj, l->data);
895
896                   if (s)
897                     {
898                        edje_object_part_text_set(it->base, l->data, s);
899                        free(s);
900                     }
901                }
902           }
903         if (it->itc->func.icon_get)
904           {
905              const Eina_List *l;
906              const char *key;
907
908              it->icons = _elm_stringlist_get(edje_object_data_get(it->base, "icons"));
909              EINA_LIST_FOREACH(it->icons, l, key)
910                {
911                   Evas_Object *ic = it->itc->func.icon_get(it->data, it->wd->obj, l->data);
912
913                   if (ic)
914                     {
915                        it->icon_objs = eina_list_append(it->icon_objs, ic);
916                        edje_object_part_swallow(it->base, key, ic);
917                        evas_object_show(ic);
918                        elm_widget_sub_object_add(it->wd->obj, ic);
919                     }
920                }
921           }
922         if (it->itc->func.state_get)
923           {
924              const Eina_List *l;
925              const char *key;
926
927              it->states = _elm_stringlist_get(edje_object_data_get(it->base, "states"));
928              EINA_LIST_FOREACH(it->states, l, key)
929                {
930                   Eina_Bool on = it->itc->func.state_get(it->data, it->wd->obj, l->data);
931
932                   if (on)
933                     {
934                        snprintf(buf, sizeof(buf), "elm,state,%s,active", key);
935                        edje_object_signal_emit(it->base, buf, "elm");
936                     }
937                }
938           }
939         if (!it->mincalcd)
940           {
941              Evas_Coord mw = -1, mh = -1;
942              
943              if (!it->display_only)
944                elm_coords_finger_size_adjust(1, &mw, 1, &mh);
945              edje_object_size_min_restricted_calc(it->base, &mw, &mh, mw, mh);
946              if (!it->display_only)
947                elm_coords_finger_size_adjust(1, &mw, 1, &mh);
948              it->w = it->minw = mw;
949              it->h = it->minh = mh;
950              it->mincalcd = EINA_TRUE;
951
952              if (in == 0 && it->wd->homogeneous)
953                {
954                   it->wd->item_width = mw;
955                   it->wd->item_height = mh;
956                }
957           }
958         if (!calc) evas_object_show(it->base);
959      }
960    it->realized = EINA_TRUE;
961    it->want_unrealize = EINA_FALSE;
962 }
963
964 static void
965 _item_unrealize(Elm_Genlist_Item *it)
966 {
967    Evas_Object *icon;
968
969    if (!it->realized) return;
970    if (it->long_timer)
971      {
972         ecore_timer_del(it->long_timer);
973         it->long_timer = NULL;
974      }
975    evas_object_del(it->base);
976    it->base = NULL;
977    evas_object_del(it->spacer);
978    it->spacer = NULL;
979    _elm_stringlist_free(it->labels);
980    it->labels = NULL;
981    _elm_stringlist_free(it->icons);
982    it->icons = NULL;
983    _elm_stringlist_free(it->states);
984
985    EINA_LIST_FREE(it->icon_objs, icon) 
986      evas_object_del(icon);
987
988    it->states = NULL;
989    it->realized = EINA_FALSE;
990    it->want_unrealize = EINA_FALSE;
991 }
992
993 static int
994 _item_block_recalc(Item_Block *itb, int in, int qadd, int norender)
995 {
996    const Eina_List *l;
997    Elm_Genlist_Item *it;
998    Evas_Coord minw = 0, minh = 0;
999    int showme = 0, changed = 0;
1000    Evas_Coord y = 0;
1001
1002    itb->num = in;
1003    EINA_LIST_FOREACH(itb->items, l, it)
1004      {
1005         if (it->delete_me) continue;
1006         showme |= it->showme;
1007         if (!itb->realized)
1008           {
1009              if (qadd)
1010                {
1011                   if (!it->mincalcd) changed = 1;
1012                   if (changed)
1013                     {
1014                        _item_realize(it, in, 1);
1015                        _item_unrealize(it);
1016                     }
1017                }
1018              else
1019                {
1020                   _item_realize(it, in, 1);
1021                   _item_unrealize(it);
1022                }
1023           }
1024         else
1025           {
1026              Eina_Bool was_realized = it->realized;
1027
1028              _item_realize(it, in, 0);
1029              if (!was_realized)
1030                evas_object_smart_callback_call(it->wd->obj, "realized", it);
1031           }
1032         minh += it->minh;
1033         if (minw < it->minw) minw = it->minw;
1034         in++;
1035         it->x = 0;
1036         it->y = y;
1037         y += it->h;
1038      }
1039    itb->minw = minw;
1040    itb->minh = minh;
1041    itb->changed = EINA_FALSE;
1042    /* force an evas norender to garbage collect deleted objects */
1043    if (norender) evas_norender(evas_object_evas_get(itb->wd->obj));
1044    return showme;
1045 }
1046
1047 static void
1048 _item_block_realize(Item_Block *itb, int in, int full)
1049 {
1050    const Eina_List *l;
1051    Elm_Genlist_Item *it;
1052
1053    if (itb->realized) return;
1054    EINA_LIST_FOREACH(itb->items, l, it)
1055      {
1056         if (it->delete_me) continue;
1057         if (full)
1058           {
1059              Eina_Bool was_realized = it->realized;
1060
1061              _item_realize(it, in, 0);
1062              if (!was_realized)
1063                evas_object_smart_callback_call(it->wd->obj, "realized", it);
1064           }
1065         in++;
1066      }
1067    itb->realized = EINA_TRUE;
1068    itb->want_unrealize = EINA_FALSE;
1069 }
1070
1071 static void
1072 _item_block_unrealize(Item_Block *itb)
1073 {
1074    const Eina_List *l;
1075    Elm_Genlist_Item *it;
1076    int dragging = 0;
1077
1078    if (!itb->realized) return;
1079    EINA_LIST_FOREACH(itb->items, l, it)
1080      {
1081         if (it->dragging)
1082           {
1083              dragging = 1;
1084              it->want_unrealize = EINA_TRUE;
1085           }
1086         else
1087           _item_unrealize(it);
1088      }
1089    if (!dragging)
1090      {
1091         itb->realized = EINA_FALSE;
1092         itb->want_unrealize = EINA_TRUE;
1093      }
1094    else
1095      itb->want_unrealize = EINA_FALSE;
1096 }
1097
1098 static void
1099 _item_block_position(Item_Block *itb, int in)
1100 {
1101    const Eina_List *l;
1102    Elm_Genlist_Item *it;
1103    Evas_Coord y = 0, ox, oy, ow, oh, cvx, cvy, cvw, cvh;
1104    int vis;
1105
1106    evas_object_geometry_get(itb->wd->pan_smart, &ox, &oy, &ow, &oh);
1107    evas_output_viewport_get(evas_object_evas_get(itb->wd->obj), &cvx, &cvy, &cvw, &cvh);
1108    EINA_LIST_FOREACH(itb->items, l, it)
1109      {
1110         if (it->delete_me) continue;
1111         it->x = 0;
1112         it->y = y;
1113         it->w = itb->w;
1114         vis = (ELM_RECTS_INTERSECT(itb->x - it->wd->pan_x + ox,
1115                                    itb->y - it->wd->pan_y + oy,
1116                                    itb->w, itb->h,
1117                                    cvx, cvy, cvw, cvh));
1118         if ((itb->realized) && (!it->realized))
1119           {
1120              if (vis)
1121                {
1122                   Eina_Bool was_realized = it->realized;
1123
1124                   _item_realize(it, in, 0);
1125                   if (!was_realized)
1126                     evas_object_smart_callback_call(it->wd->obj, 
1127                                                     "realized", it);
1128                }
1129           }
1130         if (it->realized)
1131           {
1132              if (vis)
1133                {
1134                   evas_object_resize(it->base, it->w, it->h);
1135                   evas_object_move(it->base,
1136                                    ox + itb->x + it->x - itb->wd->pan_x,
1137                                    oy + itb->y + it->y - itb->wd->pan_y);
1138                   evas_object_show(it->base);
1139                }
1140              else
1141                {
1142                   if (!it->dragging)
1143                     _item_unrealize(it);
1144                }
1145           }
1146         y += it->h;
1147         in++;
1148      }
1149 }
1150
1151 static void
1152 _calc_job(void *data)
1153 {
1154    Widget_Data *wd = data;
1155    Item_Block *itb;
1156    Evas_Coord minw = -1, minh = 0, y = 0, ow, oh;
1157    Item_Block *chb = NULL;
1158    int in = 0, minw_change = 0;
1159    if (!wd) return;
1160    EINA_INLIST_FOREACH(wd->blocks, itb)
1161      {
1162         int showme = 0;
1163
1164         itb->num = in;
1165         showme = itb->showme;
1166         itb->showme = 0;
1167         if (chb)
1168           {
1169              if (itb->realized) _item_block_unrealize(itb);
1170           }
1171         if (itb->changed)
1172           {
1173              if (itb->realized) _item_block_unrealize(itb);
1174              showme = _item_block_recalc(itb, in, 0, 1);
1175              chb = itb;
1176           }
1177         itb->y = y;
1178         itb->x = 0;
1179         minh += itb->minh;
1180         if (minw == -1) minw = itb->minw;
1181         else if (minw < itb->minw)
1182           {
1183              minw = itb->minw;
1184              minw_change = 1;
1185           }
1186         itb->w = minw;
1187         itb->h = itb->minh;
1188         y += itb->h;
1189         in += itb->count;
1190         if (showme)
1191           {
1192              wd->show_item->showme = 0;
1193              if (wd->bring_in)
1194                elm_smart_scroller_region_bring_in(wd->scr,
1195                                                   wd->show_item->x + wd->show_item->block->x,
1196                                                   wd->show_item->y + wd->show_item->block->y,
1197                                                   wd->show_item->block->w,
1198                                                   wd->show_item->h);
1199              else
1200                elm_smart_scroller_child_region_show(wd->scr,
1201                                                     wd->show_item->x + wd->show_item->block->x,
1202                                                     wd->show_item->y + wd->show_item->block->y,
1203                                                     wd->show_item->block->w,
1204                                                     wd->show_item->h);
1205              wd->show_item = NULL;
1206              showme = 0;
1207           }
1208      }
1209    if (minw_change)
1210      {
1211         EINA_INLIST_FOREACH(wd->blocks, itb)
1212           {
1213              itb->minw = minw;
1214              itb->w = itb->minw;
1215           }
1216      }
1217    if ((chb) && (EINA_INLIST_GET(chb)->next))
1218      {
1219         EINA_INLIST_FOREACH(EINA_INLIST_GET(chb)->next, itb)
1220           if (itb->realized) _item_block_unrealize(itb);
1221      }
1222    evas_object_geometry_get(wd->pan_smart, NULL, NULL, &ow, &oh);
1223    if (minw < ow) minw = ow;
1224    if ((minw != wd->minw) || (minh != wd->minh))
1225      {
1226         wd->minw = minw;
1227         wd->minh = minh;
1228         evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
1229         _sizing_eval(wd->obj);
1230      }
1231    wd->calc_job = NULL;
1232    evas_object_smart_changed(wd->pan_smart);
1233 }
1234
1235 static void
1236 _update_job(void *data)
1237 {
1238    Widget_Data *wd = data;
1239    Eina_List *l2;
1240    Item_Block *itb;
1241    int num, num0, position = 0, recalc = 0;
1242    if (!wd) return;
1243    wd->update_job = NULL;
1244    num = 0;
1245    EINA_INLIST_FOREACH(wd->blocks, itb)
1246      {
1247         Evas_Coord itminw, itminh;
1248         Elm_Genlist_Item *it;
1249
1250         if (!itb->updateme)
1251           {
1252              num += itb->count;
1253              if (position)
1254                _item_block_position(itb, num);
1255              continue;
1256           }
1257         num0 = num;
1258         recalc = 0;
1259         EINA_LIST_FOREACH(itb->items, l2, it)
1260           {
1261              if (it->updateme)
1262                {
1263                   itminw = it->w;
1264                   itminh = it->h;
1265
1266                   it->updateme = 0;
1267                   if (it->realized)
1268                     {
1269                        _item_unrealize(it);
1270                        _item_realize(it, num, 0);
1271                        evas_object_smart_callback_call(it->wd->obj, 
1272                                                        "realized", it);
1273                     }
1274                   else
1275                     {
1276                        _item_realize(it, num, 1);
1277                        _item_unrealize(it);
1278                     }
1279                   if ((it->minw != itminw) || (it->minh != itminh))
1280                     recalc = 1;
1281                }
1282              num++;
1283           }
1284         itb->updateme = 0;
1285         if (recalc)
1286           {
1287              position = 1;
1288              itb->changed = EINA_TRUE;
1289              _item_block_recalc(itb, num0, 0, 1);
1290              _item_block_position(itb, num0);
1291           }
1292      }
1293    if (position)
1294      {
1295         if (wd->calc_job) ecore_job_del(wd->calc_job);
1296         wd->calc_job = ecore_job_add(_calc_job, wd);
1297      }
1298 }
1299
1300 static void
1301 _pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
1302 {
1303    Pan *sd = evas_object_smart_data_get(obj);
1304 //   Evas_Coord ow, oh;
1305 //   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
1306 //   ow = sd->wd->minw - ow;
1307 //   if (ow < 0) ow = 0;
1308 //   oh = sd->wd->minh - oh;
1309 //   if (oh < 0) oh = 0;
1310 //   if (x < 0) x = 0;
1311 //   if (y < 0) y = 0;
1312 //   if (x > ow) x = ow;
1313 //   if (y > oh) y = oh;
1314    if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return;
1315    sd->wd->pan_x = x;
1316    sd->wd->pan_y = y;
1317    evas_object_smart_changed(obj);
1318 }
1319
1320 static void
1321 _pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
1322 {
1323    Pan *sd = evas_object_smart_data_get(obj);
1324
1325    if (x) *x = sd->wd->pan_x;
1326    if (y) *y = sd->wd->pan_y;
1327 }
1328
1329 static void
1330 _pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
1331 {
1332    Pan *sd = evas_object_smart_data_get(obj);
1333    Evas_Coord ow, oh;
1334
1335    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
1336    ow = sd->wd->minw - ow;
1337    if (ow < 0) ow = 0;
1338    oh = sd->wd->minh - oh;
1339    if (oh < 0) oh = 0;
1340    if (x) *x = ow;
1341    if (y) *y = oh;
1342 }
1343
1344 static void
1345 _pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
1346 {
1347    Pan *sd = evas_object_smart_data_get(obj);
1348
1349    if (w) *w = sd->wd->minw;
1350    if (h) *h = sd->wd->minh;
1351 }
1352
1353 static void
1354 _pan_add(Evas_Object *obj)
1355 {
1356    Pan *sd;
1357    Evas_Object_Smart_Clipped_Data *cd;
1358
1359    _pan_sc.add(obj);
1360    cd = evas_object_smart_data_get(obj);
1361    sd = ELM_NEW(Pan);
1362    if (!sd) return;
1363    sd->__clipped_data = *cd;
1364    free(cd);
1365    evas_object_smart_data_set(obj, sd);
1366 }
1367
1368 static void
1369 _pan_del(Evas_Object *obj)
1370 {
1371    Pan *sd = evas_object_smart_data_get(obj);
1372
1373    if (!sd) return;
1374    _pan_sc.del(obj);
1375 }
1376
1377 static void
1378 _pan_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
1379 {
1380    Pan *sd = evas_object_smart_data_get(obj);
1381    Evas_Coord ow, oh;
1382
1383    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
1384    if ((ow == w) && (oh == h)) return;
1385    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
1386    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
1387 }
1388
1389 static void
1390 _pan_calculate(Evas_Object *obj)
1391 {
1392    Pan *sd = evas_object_smart_data_get(obj);
1393    Item_Block *itb;
1394    Evas_Coord ox, oy, ow, oh, cvx, cvy, cvw, cvh;
1395    int in = 0;
1396
1397    evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
1398    evas_output_viewport_get(evas_object_evas_get(obj), &cvx, &cvy, &cvw, &cvh);
1399    EINA_INLIST_FOREACH(sd->wd->blocks, itb)
1400      {
1401         itb->w = sd->wd->minw;
1402         if (ELM_RECTS_INTERSECT(itb->x - sd->wd->pan_x + ox,
1403                                 itb->y - sd->wd->pan_y + oy,
1404                                 itb->w, itb->h,
1405                                 cvx, cvy, cvw, cvh))
1406           {
1407              if ((!itb->realized) || (itb->changed))
1408                _item_block_realize(itb, in, 0);
1409              _item_block_position(itb,  in);
1410           }
1411         else
1412           {
1413              if (itb->realized) _item_block_unrealize(itb);
1414           }
1415         in += itb->count;
1416      }
1417 }
1418
1419 static void
1420 _pan_move(Evas_Object *obj, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
1421 {
1422    Pan *sd = evas_object_smart_data_get(obj);
1423
1424    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
1425    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
1426 }
1427
1428 static void
1429 _hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1430 {
1431    Widget_Data *wd = elm_widget_data_get(obj);
1432    if (!wd) return;
1433    elm_smart_scroller_hold_set(wd->scr, 1);
1434 }
1435
1436 static void
1437 _hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1438 {
1439    Widget_Data *wd = elm_widget_data_get(obj);
1440    if (!wd) return;
1441    elm_smart_scroller_hold_set(wd->scr, 0);
1442 }
1443
1444 static void
1445 _freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1446 {
1447    Widget_Data *wd = elm_widget_data_get(obj);
1448    if (!wd) return;
1449    elm_smart_scroller_freeze_set(wd->scr, 1);
1450 }
1451
1452 static void
1453 _freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1454 {
1455    Widget_Data *wd = elm_widget_data_get(obj);
1456    if (!wd) return;
1457    elm_smart_scroller_freeze_set(wd->scr, 0);
1458 }
1459
1460 /**
1461  * Add a new Genlist object
1462  *
1463  * @param parent The parent object
1464  * @return The new object or NULL if it cannot be created
1465  *
1466  * @ingroup Genlist
1467  */
1468 EAPI Evas_Object *
1469 elm_genlist_add(Evas_Object *parent)
1470 {
1471    Evas_Object *obj;
1472    Evas *e;
1473    Widget_Data *wd;
1474    Evas_Coord minw, minh;
1475    static Evas_Smart *smart = NULL;
1476
1477    wd = ELM_NEW(Widget_Data);
1478    e = evas_object_evas_get(parent);
1479    obj = elm_widget_add(e);
1480    ELM_SET_WIDTYPE(widtype, "genlist");
1481    elm_widget_type_set(obj, "genlist");
1482    elm_widget_sub_object_add(parent, obj);
1483    elm_widget_data_set(obj, wd);
1484    elm_widget_del_hook_set(obj, _del_hook);
1485    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
1486    elm_widget_theme_hook_set(obj, _theme_hook);
1487
1488    wd->scr = elm_smart_scroller_add(e);
1489    elm_smart_scroller_widget_set(wd->scr, obj);
1490    elm_smart_scroller_object_theme_set(obj, wd->scr, "genlist", "base", elm_widget_style_get(obj));
1491    elm_widget_resize_object_set(obj, wd->scr);
1492
1493    elm_smart_scroller_bounce_allow_set(wd->scr, 0, 1);
1494
1495    wd->obj = obj;
1496    wd->mode = ELM_LIST_SCROLL;
1497    wd->max_items_per_block = 32;
1498
1499    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
1500    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
1501    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
1502    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
1503
1504    if (!smart)
1505      {
1506         static Evas_Smart_Class sc;
1507
1508         evas_object_smart_clipped_smart_set(&_pan_sc);
1509         sc = _pan_sc;
1510         sc.name = "elm_genlist_pan";
1511         sc.version = EVAS_SMART_CLASS_VERSION;
1512         sc.add = _pan_add;
1513         sc.del = _pan_del;
1514         sc.resize = _pan_resize;
1515         sc.move = _pan_move;
1516         sc.calculate = _pan_calculate;
1517         smart = evas_smart_class_new(&sc);
1518      }
1519    if (smart)
1520      {
1521         wd->pan_smart = evas_object_smart_add(e, smart);
1522         wd->pan = evas_object_smart_data_get(wd->pan_smart);
1523         wd->pan->wd = wd;
1524      }
1525
1526    elm_smart_scroller_extern_pan_set(wd->scr, wd->pan_smart,
1527                                      _pan_set, _pan_get,
1528                                      _pan_max_get, _pan_child_size_get);
1529
1530    edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr),
1531                              &minw, &minh);
1532    evas_object_size_hint_min_set(obj, minw, minh);
1533
1534    _sizing_eval(obj);
1535    return obj;
1536 }
1537
1538 static Elm_Genlist_Item *
1539 _item_new(Widget_Data *wd, const Elm_Genlist_Item_Class *itc,
1540           const void *data, Elm_Genlist_Item *parent,
1541           Elm_Genlist_Item_Flags flags,
1542           Evas_Smart_Cb func,
1543           const void *func_data)
1544 {
1545    Elm_Genlist_Item *it;
1546
1547    it = calloc(1, sizeof(Elm_Genlist_Item));
1548    if (!it) return NULL;
1549    it->wd = wd;
1550    it->itc = itc;
1551    it->data = data;
1552    it->parent = parent;
1553    it->flags = flags;
1554    it->func.func = func;
1555    it->func.data = func_data;
1556    return it;
1557 }
1558
1559 static void
1560 _item_block_add(Widget_Data *wd, Elm_Genlist_Item *it)
1561 {
1562    Item_Block *itb = NULL;
1563
1564    if (!it->rel)
1565      {
1566         newblock:
1567         if (it->rel)
1568           {
1569              itb = calloc(1, sizeof(Item_Block));
1570              if (!itb) return;
1571              itb->wd = wd;
1572              if (!it->rel->block)
1573                {
1574                   wd->blocks = 
1575                     eina_inlist_append(wd->blocks, EINA_INLIST_GET(itb));
1576                   itb->items = eina_list_append(itb->items, it);
1577                }
1578              else
1579                {
1580                   if (it->before)
1581                     {
1582                        wd->blocks = 
1583                          eina_inlist_prepend_relative(wd->blocks, 
1584                                                       EINA_INLIST_GET(itb), 
1585                                                       EINA_INLIST_GET(it->rel->block));
1586                        itb->items = 
1587                          eina_list_prepend_relative(itb->items, it, it->rel);
1588                     }
1589                   else
1590                     {
1591                        wd->blocks = 
1592                          eina_inlist_append_relative(wd->blocks, 
1593                                                      EINA_INLIST_GET(itb), 
1594                                                      EINA_INLIST_GET(it->rel->block));
1595                        itb->items = 
1596                          eina_list_append_relative(itb->items, it, it->rel);
1597                     }
1598                }
1599           }
1600         else
1601           {
1602              if (it->before)
1603                {
1604                   if (wd->blocks)
1605                     {
1606                        itb = (Item_Block *)(wd->blocks);
1607                        if (itb->count >= wd->max_items_per_block)
1608                          {
1609                             itb = calloc(1, sizeof(Item_Block));
1610                             if (!itb) return;
1611                             itb->wd = wd;
1612                             wd->blocks = 
1613                               eina_inlist_prepend(wd->blocks, 
1614                                                   EINA_INLIST_GET(itb));
1615                          }
1616                     }
1617                   else
1618                     {
1619                        itb = calloc(1, sizeof(Item_Block));
1620                        if (!itb) return;
1621                        itb->wd = wd;
1622                        wd->blocks = 
1623                          eina_inlist_prepend(wd->blocks, EINA_INLIST_GET(itb));
1624                     }
1625                   itb->items = eina_list_prepend(itb->items, it);
1626                }
1627              else
1628                {
1629                   if (wd->blocks)
1630                     {
1631                        itb = (Item_Block *)(wd->blocks->last);
1632                        if (itb->count >= wd->max_items_per_block)
1633                          {
1634                             itb = calloc(1, sizeof(Item_Block));
1635                             if (!itb) return;
1636                             itb->wd = wd;
1637                             wd->blocks = 
1638                               eina_inlist_append(wd->blocks, 
1639                                                  EINA_INLIST_GET(itb));
1640                          }
1641                     }
1642                   else
1643                     {
1644                        itb = calloc(1, sizeof(Item_Block));
1645                        if (!itb) return;
1646                        itb->wd = wd;
1647                        wd->blocks = 
1648                          eina_inlist_append(wd->blocks, EINA_INLIST_GET(itb));
1649                     }
1650                   itb->items = eina_list_append(itb->items, it);
1651                }
1652           }
1653      }
1654    else
1655      {
1656         itb = it->rel->block;
1657         if (!itb) goto newblock;
1658         if (it->before)
1659           itb->items = eina_list_prepend_relative(itb->items, it, it->rel);
1660         else
1661           itb->items = eina_list_append_relative(itb->items, it, it->rel);
1662      }
1663    itb->count++;
1664    itb->changed = EINA_TRUE;
1665    it->block = itb;
1666    if (itb->wd->calc_job) ecore_job_del(itb->wd->calc_job);
1667    itb->wd->calc_job = ecore_job_add(_calc_job, itb->wd);
1668    if (it->rel)
1669      {
1670         it->rel->relcount--;
1671         if ((it->rel->delete_me) && (it->rel->relcount == 0))
1672           _item_del(it->rel);
1673         it->rel = NULL;
1674      }
1675    if (itb->count > itb->wd->max_items_per_block)
1676      {
1677         int newc;
1678         Item_Block *itb2;
1679         Elm_Genlist_Item *it2;
1680
1681         newc = itb->count / 2;
1682         itb2 = calloc(1, sizeof(Item_Block));
1683         if (!itb2) return;
1684         itb2->wd = wd;
1685         wd->blocks = 
1686           eina_inlist_append_relative(wd->blocks, EINA_INLIST_GET(itb2), 
1687                                       EINA_INLIST_GET(itb));
1688         itb2->changed = EINA_TRUE;
1689         while ((itb->count > newc) && (itb->items))
1690           {
1691              Eina_List *l;
1692
1693              l = eina_list_last(itb->items);
1694              it2 = l->data;
1695              itb->items = eina_list_remove_list(itb->items, l);
1696              itb->count--;
1697
1698              itb2->items = eina_list_prepend(itb2->items, it2);
1699              it2->block = itb2;
1700              itb2->count++;
1701           }
1702      }
1703 }
1704
1705 static int
1706 _queue_proecess(Widget_Data *wd, int norender)
1707 {
1708    int n, showme = 0;
1709    double t0, t;
1710
1711    t0 = ecore_time_get();
1712    for (n = 0; (wd->queue) && (n < 128); n++)
1713      {
1714         Elm_Genlist_Item *it;
1715
1716         it = wd->queue->data;
1717         wd->queue = eina_list_remove_list(wd->queue, wd->queue);
1718         it->queued = EINA_FALSE;
1719         _item_block_add(wd, it);
1720         t = ecore_time_get();
1721         if (it->block->changed)
1722           {
1723              showme = _item_block_recalc(it->block, it->block->num, 1, norender);
1724              it->block->changed = 0;
1725           }
1726         if (showme) it->block->showme = 1;
1727         if (eina_inlist_count(wd->blocks) > 1)
1728           {
1729              if ((t - t0) > (ecore_animator_frametime_get())) break;
1730           }
1731      }
1732    return n;
1733 }
1734
1735 static int
1736 _item_idler(void *data)
1737 {
1738    Widget_Data *wd = data;
1739    
1740    if (_queue_proecess(wd, 1) > 0)
1741      {
1742         if (wd->calc_job) ecore_job_del(wd->calc_job);
1743         wd->calc_job = ecore_job_add(_calc_job, wd);
1744      }
1745    if (!wd->queue)
1746      {
1747         wd->queue_idler = NULL;
1748         return 0;
1749      }
1750    return 1;
1751 }
1752
1753 static void
1754 _item_queue(Widget_Data *wd, Elm_Genlist_Item *it)
1755 {
1756    if (it->queued) return;
1757    it->queued = EINA_TRUE;
1758    wd->queue = eina_list_append(wd->queue, it);
1759    while ((wd->queue) && ((!wd->blocks) || (!wd->blocks->next)))
1760      {
1761         if (wd->queue_idler)
1762           {
1763              ecore_idler_del(wd->queue_idler);
1764              wd->queue_idler = NULL;
1765           }
1766         _queue_proecess(wd, 0);
1767      }
1768    if (!wd->queue_idler) wd->queue_idler = ecore_idler_add(_item_idler, wd);
1769 }
1770
1771 /**
1772  * Append item to the end of the genlist
1773  *
1774  * This appends the given item to the end of the list or the end of the
1775  * children if the parent is given.
1776  *
1777  * @param obj The genlist object
1778  * @param itc The item class for the item
1779  * @param data The item data
1780  * @param parent The parent item, or NULL if none
1781  * @param flags Item flags
1782  * @param func Convenience function called when item selected
1783  * @param func_data Data passed to @p func above.
1784  * @return A handle to the item added or NULL if not possible
1785  *
1786  * @ingroup Genlist
1787  */
1788 EAPI Elm_Genlist_Item *
1789 elm_genlist_item_append(Evas_Object *obj, const Elm_Genlist_Item_Class *itc,
1790                         const void *data, Elm_Genlist_Item *parent,
1791                         Elm_Genlist_Item_Flags flags,
1792                         Evas_Smart_Cb func, const void *func_data)
1793 {
1794    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1795    Widget_Data *wd = elm_widget_data_get(obj);
1796    Elm_Genlist_Item *it = _item_new(wd, itc, data, parent, flags, func, func_data);
1797    if (!wd) return NULL;
1798    if (!it) return NULL;
1799    if (!it->parent)
1800      {
1801         wd->items = eina_inlist_append(wd->items, EINA_INLIST_GET(it));
1802         it->rel = NULL;
1803         it->before = 0;
1804      }
1805    else
1806      {
1807         Elm_Genlist_Item *it2 = NULL;
1808         Eina_List *ll = eina_list_last(it->parent->items);
1809         if (ll) it2 = ll->data;
1810         it->parent->items = eina_list_append(it->parent->items, it);
1811         if (!it2) it2 = it->parent;
1812         wd->items = 
1813           eina_inlist_append_relative(wd->items, EINA_INLIST_GET(it), 
1814                                       EINA_INLIST_GET(it2));
1815         it->rel = it2;
1816         it->rel->relcount++;
1817         it->before = 0;
1818      }
1819    _item_queue(wd, it);
1820    return it;
1821 }
1822
1823 /**
1824  * Prepend item at start of the genlist
1825  *
1826  * This adds an item to the beginning of the list or beginning of the children
1827  * of the parent if given.
1828  *
1829  * @param obj The genlist object
1830  * @param itc The item class for the item
1831  * @param data The item data
1832  * @param parent The parent item, or NULL if none
1833  * @param flags Item flags
1834  * @param func Convenience function called when item selected
1835  * @param func_data Data passed to @p func above.
1836  * @return A handle to the item added or NULL if not possible
1837  *
1838  * @ingroup Genlist
1839  */
1840 EAPI Elm_Genlist_Item *
1841 elm_genlist_item_prepend(Evas_Object *obj, const Elm_Genlist_Item_Class *itc,
1842                          const void *data, Elm_Genlist_Item *parent,
1843                          Elm_Genlist_Item_Flags flags,
1844                          Evas_Smart_Cb func, const void *func_data)
1845 {
1846    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1847    Widget_Data *wd = elm_widget_data_get(obj);
1848    Elm_Genlist_Item *it = _item_new(wd, itc, data, parent, flags, func, func_data);
1849    if (!wd) return NULL;
1850    if (!it) return NULL;
1851    if (!it->parent)
1852      wd->items = eina_inlist_prepend(wd->items, EINA_INLIST_GET(it));
1853    else
1854      {
1855         printf("FIXME: 12 tree not handled yet\n");
1856      }
1857    it->rel = NULL;
1858    it->before = 1;
1859    _item_queue(wd, it);
1860    return it;
1861 }
1862
1863 /**
1864  * Insert item before another in the genlist
1865  *
1866  * This inserts an item before another in the list. It will be in the same tree
1867  * level as the item it is inseted before.
1868  *
1869  * @param obj The genlist object
1870  * @param itc The item class for the item
1871  * @param data The item data
1872  * @param before The item to insert before
1873  * @param flags Item flags
1874  * @param func Convenience function called when item selected
1875  * @param func_data Data passed to @p func above.
1876  * @return A handle to the item added or NULL if not possible
1877  *
1878  * @ingroup Genlist
1879  */
1880 EAPI Elm_Genlist_Item *
1881 elm_genlist_item_insert_before(Evas_Object *obj, const Elm_Genlist_Item_Class *itc,
1882                                const void *data, Elm_Genlist_Item *before,
1883                                Elm_Genlist_Item_Flags flags,
1884                                Evas_Smart_Cb func, const void *func_data)
1885 {
1886    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1887    Widget_Data *wd = elm_widget_data_get(obj);
1888    Elm_Genlist_Item *it = _item_new(wd, itc, data, NULL, flags, func, func_data);
1889    if (!wd) return NULL;
1890    if (!it) return NULL;
1891    if (!it->parent)
1892      wd->items = eina_inlist_prepend_relative(wd->items, EINA_INLIST_GET(it), 
1893                                               EINA_INLIST_GET(before));
1894    else
1895      {
1896         printf("FIXME: 13 tree not handled yet\n");
1897      }
1898    it->rel = before;
1899    it->rel->relcount++;
1900    it->before = 1;
1901    _item_queue(wd, it);
1902    return it;
1903 }
1904
1905 /**
1906  * Insert and item after another in the genlst
1907  *
1908  * This inserts an item after another in the list. It will be in the same tree
1909  * level as the item it is inseted after.
1910  *
1911  * @param obj The genlist object
1912  * @param itc The item class for the item
1913  * @param data The item data
1914  * @param after The item to insert after
1915  * @param flags Item flags
1916  * @param func Convenience function called when item selected
1917  * @param func_data Data passed to @p func above.
1918  * @return A handle to the item added or NULL if not possible
1919  *
1920  * @ingroup Genlist
1921  */
1922 EAPI Elm_Genlist_Item *
1923 elm_genlist_item_insert_after(Evas_Object *obj, const Elm_Genlist_Item_Class *itc,
1924                               const void *data, Elm_Genlist_Item *after,
1925                               Elm_Genlist_Item_Flags flags,
1926                               Evas_Smart_Cb func, const void *func_data)
1927 {
1928    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1929    Widget_Data *wd = elm_widget_data_get(obj);
1930    Elm_Genlist_Item *it = _item_new(wd, itc, data, NULL, flags, func, func_data);
1931    if (!wd) return NULL;
1932    if (!it) return NULL;
1933    if (!it->parent)
1934      wd->items = eina_inlist_append_relative(wd->items, EINA_INLIST_GET(it), 
1935                                              EINA_INLIST_GET(after));
1936    else
1937      {
1938         printf("FIXME: 14 tree not handled yet\n");
1939      }
1940    it->rel = after;
1941    it->rel->relcount++;
1942    it->before = 0;
1943    _item_queue(wd, it);
1944    return it;
1945 }
1946
1947 /**
1948  * Clear the genlist
1949  *
1950  * This clears all items in the list, leaving it empty.
1951  *
1952  * @param obj The genlist object
1953  *
1954  * @ingroup Genlist
1955  */
1956 EAPI void
1957 elm_genlist_clear(Evas_Object *obj)
1958 {
1959    ELM_CHECK_WIDTYPE(obj, widtype);
1960    Widget_Data *wd = elm_widget_data_get(obj);
1961    if (!wd) return;
1962    while (wd->items)
1963      {
1964         Elm_Genlist_Item *it = (Elm_Genlist_Item *)(wd->items);
1965
1966         wd->items = eina_inlist_remove(wd->items, wd->items);
1967         if (it->realized) _item_unrealize(it);
1968         if (it->itc->func.del) it->itc->func.del(it->data, it->wd->obj);
1969         if (it->long_timer) ecore_timer_del(it->long_timer);
1970         free(it);
1971      }
1972    while (wd->blocks)
1973      {
1974         Item_Block *itb = (Item_Block *)(wd->blocks);
1975
1976         wd->blocks = eina_inlist_remove(wd->blocks, wd->blocks);
1977         if (itb->items) eina_list_free(itb->items);
1978         free(itb);
1979      }
1980    if (wd->calc_job)
1981      {
1982         ecore_job_del(wd->calc_job);
1983         wd->calc_job = NULL;
1984      }
1985    if (wd->queue_idler)
1986      {
1987         ecore_idler_del(wd->queue_idler);
1988         wd->queue_idler = NULL;
1989      }
1990    if (wd->queue)
1991      {
1992         eina_list_free(wd->queue);
1993         wd->queue = NULL;
1994      }
1995    if (wd->selected)
1996      {
1997         eina_list_free(wd->selected);
1998         wd->selected = NULL;
1999      }
2000    wd->show_item = NULL;
2001    wd->pan_x = 0;
2002    wd->pan_y = 0;
2003    wd->minw = 0;
2004    wd->minh = 0;
2005    evas_object_size_hint_min_set(wd->pan_smart, wd->minw, wd->minh);
2006    evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
2007    _sizing_eval(obj);
2008 }
2009
2010 /**
2011  * Enable or disable multi-select in the genlist
2012  *
2013  * This enables (EINA_TRUE) or disableds (EINA_FALSE) multi-select in the list. This allows
2014  * more than 1 item to be selected.
2015  *
2016  * @param obj The genlist object
2017  * @param multi Multi-select enable/disable
2018  *
2019  * @ingroup Genlist
2020  */
2021 EAPI void
2022 elm_genlist_multi_select_set(Evas_Object *obj, Eina_Bool multi)
2023 {
2024    ELM_CHECK_WIDTYPE(obj, widtype);
2025    Widget_Data *wd = elm_widget_data_get(obj);
2026    if (!wd) return;
2027    wd->multi = multi;
2028 }
2029
2030 /**
2031  * Gets if multi-select in genlist is enable or disable
2032  *
2033  * @param obj The genlist object
2034  * @return Multi-select enable/disable
2035  * (EINA_TRUE = enabled/EINA_FALSE = disabled)
2036  *
2037  * @ingroup Genlist
2038  */
2039 EAPI Eina_Bool
2040 elm_genlist_multi_select_get(const Evas_Object *obj)
2041 {
2042    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2043    Widget_Data *wd = elm_widget_data_get(obj);
2044    if (!wd) return EINA_FALSE;
2045    return wd->multi;
2046 }
2047
2048
2049 /**
2050  * Get the selectd item in the genlist
2051  *
2052  * This gets the selected item in the list (if multi-select is enabled only
2053  * the first item in the list is selected - which is not very useful, so see
2054  * elm_genlist_selected_items_get()for when multi-select is used).
2055  *
2056  * If no item is selected, NULL is returned.
2057  *
2058  * @param obj The genlist object
2059  * @return The selected item, or NULL if none.
2060  *
2061  * @ingroup Genlist
2062  */
2063 EAPI Elm_Genlist_Item *
2064 elm_genlist_selected_item_get(const Evas_Object *obj)
2065 {
2066    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2067    Widget_Data *wd = elm_widget_data_get(obj);
2068    if (!wd) return NULL;
2069    if (wd->selected) return wd->selected->data;
2070    return NULL;
2071 }
2072
2073 /**
2074  * Get a list of selected items in the genlist
2075  *
2076  * This retgurns a list of the selected items. This list pointer is only valid
2077  * so long as no items are selected or unselected (or unselected implicitly
2078  * by deletion). The list contains Elm_Genlist_Item pointers.
2079  *
2080  * @param obj The genlist object
2081  * @return The list of selected items, nor NULL if none are selected.
2082  *
2083  * @ingroup Genlist
2084  */
2085 EAPI const Eina_List *
2086 elm_genlist_selected_items_get(const Evas_Object *obj)
2087 {
2088    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2089    Widget_Data *wd = elm_widget_data_get(obj);
2090    if (!wd) return NULL;
2091    return wd->selected;
2092 }
2093
2094 /**
2095  * Get a list of realized items in genlist
2096  *
2097  * This returns a list of the realized items in the genlist. The list
2098  * contains Elm_Genlist_Item pointers. The list must be freed by the
2099  * caller when done with eina_list_free(). The item pointers in the list
2100  * are only vallid so long as those items are not deleted or the genlist is
2101  * not deleted.
2102  *
2103  * @param obj The genlist object
2104  * @return The list of realized items, nor NULL if none are realized.
2105  *
2106  * @ingroup Genlist
2107  */
2108 EAPI Eina_List *
2109 elm_genlist_realized_items_get(const Evas_Object *obj)
2110 {
2111    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2112    Widget_Data *wd = elm_widget_data_get(obj);
2113    Eina_List *list = NULL;
2114    Item_Block *itb;
2115    Eina_Bool done = EINA_FALSE;
2116    if (!wd) return NULL;
2117    EINA_INLIST_FOREACH(wd->blocks, itb)
2118      {
2119         if (itb->realized)
2120           {
2121              Eina_List *l;
2122              Elm_Genlist_Item *it;
2123              
2124              done = 1;
2125              EINA_LIST_FOREACH(itb->items, l, it)
2126                {
2127                   if (it->realized) list = eina_list_append(list, it);
2128                }
2129           }
2130         else
2131           {
2132              if (done) break;
2133           }
2134      }
2135    return list;
2136 }
2137
2138 /**
2139  * Get the item that is at the x, y canvas coords
2140  *
2141  * This returns the item at the given coordinates (which are canvas relative
2142  * not object-relative). If an item is at that coordinate, that item handle
2143  * is returned, and if @p posret is not NULL, the integer pointed to is set
2144  * to a value of -1, 0 or 1, depending if the coordinate is on the upper
2145  * portion of that item (-1), on the middle section (0) or on the lower part
2146  * (1). If NULL is returned as an item (no item found there), then posret
2147  * may indicate -1 or 1 based if the coordinate is above or below all items
2148  * respectively in the genlist.
2149  *
2150  * @param it The item
2151  * @param x The input x coordinate
2152  * @param y The input y coordinate
2153  * @param posret The position relative to the item returned here
2154  * @return The item at the coordinates or NULL if none
2155  *
2156  * @ingroup Genlist
2157  */
2158 EAPI Elm_Genlist_Item *
2159 elm_genlist_at_xy_item_get(const Evas_Object *obj, Evas_Coord x, Evas_Coord y, int *posret)
2160 {
2161    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2162    Widget_Data *wd = elm_widget_data_get(obj);
2163    Evas_Coord ox, oy, ow, oh;
2164    Item_Block *itb;
2165    Evas_Coord lasty;
2166    if (!wd) return NULL;
2167    evas_object_geometry_get(wd->pan_smart, &ox, &oy, &ow, &oh);
2168    lasty = oy;
2169    EINA_INLIST_FOREACH(wd->blocks, itb)
2170      {
2171         Eina_List *l;
2172         Elm_Genlist_Item *it;
2173
2174         if (!ELM_RECTS_INTERSECT(ox + itb->x - itb->wd->pan_x,
2175                                  oy + itb->y - itb->wd->pan_y,
2176                                  itb->w, itb->h, x, y, 1, 1))
2177           continue;
2178         EINA_LIST_FOREACH(itb->items, l, it)
2179           {
2180              Evas_Coord itx, ity;
2181
2182              itx = ox + itb->x + it->x - itb->wd->pan_x;
2183              ity = oy + itb->y + it->y - itb->wd->pan_y;
2184              if (ELM_RECTS_INTERSECT(itx, ity, it->w, it->h, x, y, 1, 1))
2185                {
2186                   if (posret)
2187                     {
2188                        if (y <= (ity + (it->h / 4))) *posret = -1;
2189                        else if (y >= (ity + it->h - (it->h / 4))) *posret = 1;
2190                        else *posret = 0;
2191                     }
2192                   return it;
2193                }
2194              lasty = ity + it->h;
2195           }
2196      }
2197    if (posret)
2198      {
2199         if (y > lasty) *posret = 1;
2200         else *posret = -1;
2201      }
2202    return NULL;
2203 }
2204
2205 /**
2206  * Get the first item in the genlist
2207  *
2208  * This returns the first item in the list.
2209  *
2210  * @param obj The genlist object
2211  * @return The first item, or NULL if none
2212  *
2213  * @ingroup Genlist
2214  */
2215 EAPI Elm_Genlist_Item *
2216 elm_genlist_first_item_get(const Evas_Object *obj)
2217 {
2218    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2219    Widget_Data *wd = elm_widget_data_get(obj);
2220    if (!wd) return NULL;
2221    if (!wd->items) return NULL;
2222    Elm_Genlist_Item *it = (Elm_Genlist_Item *)(wd->items);
2223    while ((it) && (it->delete_me))
2224      it = (Elm_Genlist_Item *)(EINA_INLIST_GET(it)->next);
2225    return it;
2226 }
2227
2228 /**
2229  * Get the last item in the genlist
2230  *
2231  * This returns the last item in the list.
2232  *
2233  * @return The last item, or NULL if none
2234  *
2235  * @ingroup Genlist
2236  */
2237 EAPI Elm_Genlist_Item *
2238 elm_genlist_last_item_get(const Evas_Object *obj)
2239 {
2240    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2241    Widget_Data *wd = elm_widget_data_get(obj);
2242    if (!wd->items) return NULL;
2243    Elm_Genlist_Item *it = (Elm_Genlist_Item *)(wd->items->last);
2244    if (!wd) return NULL;
2245    while ((it) && (it->delete_me))
2246      it = (Elm_Genlist_Item *)(EINA_INLIST_GET(it)->prev);
2247    return it;
2248 }
2249
2250 /**
2251  * Get the next item in the genlist
2252  *
2253  * This returns the item after the item @p it.
2254  *
2255  * @param it The item
2256  * @return The item after @p it, or NULL if none
2257  *
2258  * @ingroup Genlist
2259  */
2260 EAPI Elm_Genlist_Item *
2261 elm_genlist_item_next_get(const Elm_Genlist_Item *it)
2262 {
2263    while (it)
2264      {
2265         it = (Elm_Genlist_Item *)(EINA_INLIST_GET(it)->next);
2266         if ((it) && (!it->delete_me)) break;
2267      }
2268    return (Elm_Genlist_Item *)it;
2269 }
2270
2271 /**
2272  * Get the previous item in the genlist
2273  *
2274  * This returns the item before the item @p it.
2275  *
2276  * @param it The item
2277  * @return The item before @p it, or NULL if none
2278  *
2279  * @ingroup Genlist
2280  */
2281 EAPI Elm_Genlist_Item *
2282 elm_genlist_item_prev_get(const Elm_Genlist_Item *it)
2283 {
2284    while (it)
2285      {
2286         it = (Elm_Genlist_Item *)(EINA_INLIST_GET(it)->prev);
2287         if ((it) && (!it->delete_me)) break;
2288      }
2289    return (Elm_Genlist_Item *)it;
2290 }
2291
2292 /**
2293  * Get the genlist object from an item
2294  *
2295  * This returns the genlist object itself that an item belongs to.
2296  *
2297  * @param it The item
2298  * @return The genlist object
2299  *
2300  * @ingroup Genlist
2301  */
2302 EAPI Evas_Object *
2303 elm_genlist_item_genlist_get(const Elm_Genlist_Item *it)
2304 {
2305    if (!it) return NULL;
2306    return it->wd->obj;
2307 }
2308
2309 /**
2310  * Get the parent item of the given item
2311  *
2312  * This returns the prent item of the item @p it given.
2313  *
2314  * @param it The item
2315  * @return The parent of the item or NULL if none
2316  *
2317  * @ingroup Genlist
2318  */
2319 EAPI Elm_Genlist_Item *
2320 elm_genlist_item_parent_get(const Elm_Genlist_Item *it)
2321 {
2322    if (!it) return NULL;
2323    return it->parent;
2324 }
2325
2326 /**
2327  * Clear all sub-items (children) of the given item
2328  *
2329  * This clears all items that are children (or their descendants) of the
2330  * given item @p it.
2331  *
2332  * @param it The item
2333  *
2334  * @ingroup Genlist
2335  */
2336 EAPI void
2337 elm_genlist_item_subitems_clear(Elm_Genlist_Item *it)
2338 {
2339    Eina_List *tl = NULL, *l;
2340    Elm_Genlist_Item *it2;
2341
2342    if (!it) return;
2343    EINA_LIST_FOREACH(it->items, l, it2)
2344      tl = eina_list_append(tl, it2);
2345    EINA_LIST_FREE(tl, it2)
2346      elm_genlist_item_del(it2);
2347 }
2348
2349 /**
2350  * Set the selected state of an item
2351  *
2352  * This sets the selected state (1 selected, 0 not selected) of the given
2353  * item @p it.
2354  *
2355  * @param it The item
2356  * @param selected The slected state
2357  *
2358  * @ingroup Genlist
2359  */
2360 EAPI void
2361 elm_genlist_item_selected_set(Elm_Genlist_Item *it, Eina_Bool selected)
2362 {
2363    Widget_Data *wd = elm_widget_data_get(it->wd->obj);
2364    if (!wd) return;
2365    if (!it) return;
2366    if (it->delete_me) return;
2367    selected = !!selected;
2368    if (it->selected == selected) return;
2369
2370    if (selected)
2371      {
2372         if (!wd->multi)
2373           {
2374              while (wd->selected)
2375                _item_unselect(wd->selected->data);
2376           }
2377         _item_hilight(it);
2378         _item_select(it);
2379      }
2380    else
2381      _item_unselect(it);
2382 }
2383
2384 /**
2385  * Get the selected state of an item
2386  *
2387  * This gets the selected state of an item (1 selected, 0 not selected).
2388  *
2389  * @param it The item
2390  * @return The selected state
2391  *
2392  * @ingroup Genlist
2393  */
2394 EAPI Eina_Bool
2395 elm_genlist_item_selected_get(const Elm_Genlist_Item *it)
2396 {
2397    if (!it) return EINA_FALSE;
2398    return it->selected;
2399 }
2400
2401 /**
2402  * Sets the expanded state of an item (if it's a parent)
2403  *
2404  * This expands or contracts a parent iterm (thus showing or hiding the
2405  * children).
2406  *
2407  * @param it The item
2408  * @param expanded The expanded state (1 expanded, 0 not expanded).
2409  *
2410  * @ingroup Genlist
2411  */
2412 EAPI void
2413 elm_genlist_item_expanded_set(Elm_Genlist_Item *it, Eina_Bool expanded)
2414 {
2415    if (!it) return;
2416    if (it->expanded == expanded) return;
2417    it->expanded = expanded;
2418    if (it->expanded)
2419      {
2420         if (it->realized)
2421           edje_object_signal_emit(it->base, "elm,state,expanded", "elm");
2422         evas_object_smart_callback_call(it->wd->obj, "expanded", it);
2423      }
2424    else
2425      {
2426         if (it->realized)
2427           edje_object_signal_emit(it->base, "elm,state,contracted", "elm");
2428         evas_object_smart_callback_call(it->wd->obj, "contracted", it);
2429      }
2430 }
2431
2432 /**
2433  * Get the expanded state of an item
2434  *
2435  * This gets the expanded state of an item
2436  *
2437  * @param it The item
2438  * @return Thre expanded state
2439  *
2440  * @ingroup Genlist
2441  */
2442 EAPI Eina_Bool
2443 elm_genlist_item_expanded_get(const Elm_Genlist_Item *it)
2444 {
2445    if (!it) return EINA_FALSE;
2446    return it->expanded;
2447 }
2448
2449 /**
2450  * Sets the disabled state of an item.
2451  *
2452  * A disabled item cannot be selected or unselected. It will also change
2453  * appearance to appear disabled. This sets the disabled state (1 disabled, 0
2454  * not disabled).
2455  *
2456  * @param it The item
2457  * @param disabled The disabled state
2458  *
2459  * @ingroup Genlist
2460  */
2461 EAPI void
2462 elm_genlist_item_disabled_set(Elm_Genlist_Item *it, Eina_Bool disabled)
2463 {
2464    if (!it) return;
2465    if (it->disabled == disabled) return;
2466    if (it->delete_me) return;
2467    it->disabled = disabled;
2468    if (it->realized)
2469      {
2470         if (it->disabled)
2471           edje_object_signal_emit(it->base, "elm,state,disabled", "elm");
2472         else
2473           edje_object_signal_emit(it->base, "elm,state,enabled", "elm");
2474      }
2475 }
2476
2477 /**
2478  * Get the disabled state of an item
2479  *
2480  * This gets the disabld state of the given item.
2481  *
2482  * @param it The item
2483  * @return The disabled state
2484  *
2485  * @ingroup Genlist
2486  */
2487 EAPI Eina_Bool
2488 elm_genlist_item_disabled_get(const Elm_Genlist_Item *it)
2489 {
2490    if (!it) return EINA_FALSE;
2491    if (it->delete_me) return EINA_FALSE;
2492    return it->disabled;
2493 }
2494
2495 /**
2496  * Sets the display only state of an item.
2497  *
2498  * A display only item cannot be selected or unselected. It is for display
2499  * only and not selecting or otherwise clicking, dragging etc. by the user,
2500  * thus finger size rules will not be applied to this item.
2501  *
2502  * @param it The item
2503  * @param display_only The display only state
2504  *
2505  * @ingroup Genlist
2506  */
2507 EAPI void
2508 elm_genlist_item_display_only_set(Elm_Genlist_Item *it, Eina_Bool display_only)
2509 {
2510    if (!it) return;
2511    if (!it->block) return;
2512    if (it->display_only == display_only) return;
2513    if (it->delete_me) return;
2514    it->display_only = display_only;
2515    it->mincalcd = EINA_FALSE;
2516    it->updateme = EINA_TRUE;
2517    it->block->updateme = EINA_TRUE;
2518    if (it->wd->update_job) ecore_job_del(it->wd->update_job);
2519    it->wd->update_job = ecore_job_add(_update_job, it->wd);
2520 }
2521
2522 /**
2523  * Get the display only state of an item
2524  *
2525  * This gets the display only state of the given item.
2526  *
2527  * @param it The item
2528  * @return The display only state
2529  *
2530  * @ingroup Genlist
2531  */
2532 EAPI Eina_Bool
2533 elm_genlist_item_display_only_get(const Elm_Genlist_Item *it)
2534 {
2535    if (!it) return EINA_FALSE;
2536    if (it->delete_me) return EINA_FALSE;
2537    return it->display_only;
2538 }
2539
2540 /**
2541  * Show the given item
2542  *
2543  * This causes genlist to jump to the given item @p it and show it (by scrolling),
2544  * if it is not fully visible.
2545  *
2546  * @param it The item
2547  *
2548  * @ingroup Genlist
2549  */
2550 EAPI void
2551 elm_genlist_item_show(Elm_Genlist_Item *it)
2552 {
2553    if (!it) return;
2554    if (it->delete_me) return;
2555    if ((it->queued) || (!it->mincalcd))
2556      {
2557         it->wd->show_item = it;
2558         it->wd->bring_in = 1;
2559         it->showme = EINA_TRUE;
2560         return;
2561      }
2562    if (it->wd->show_item)
2563      {
2564         it->wd->show_item->showme = EINA_FALSE;
2565         it->wd->show_item = NULL;
2566      }
2567    elm_smart_scroller_child_region_show(it->wd->scr,
2568                                         it->x + it->block->x,
2569                                         it->y + it->block->y,
2570                                         it->block->w, it->h);
2571 }
2572
2573 /**
2574  * Bring in the given item
2575  *
2576  * This causes genlist to jump to the given item @p it and show it (by scrolling),
2577  * if it is not fully visible. This may use animation to do so and take a
2578  * period of time
2579  *
2580  * @param it The item
2581  *
2582  * @ingroup Genlist
2583  */
2584 EAPI void
2585 elm_genlist_item_bring_in(Elm_Genlist_Item *it)
2586 {
2587    if (!it) return;
2588    if (it->delete_me) return;
2589    if ((it->queued) || (!it->mincalcd))
2590      {
2591         it->wd->show_item = it;
2592         it->wd->bring_in = 1;
2593         it->showme = EINA_TRUE;
2594         return;
2595      }
2596    if (it->wd->show_item)
2597      {
2598         it->wd->show_item->showme = EINA_FALSE;
2599         it->wd->show_item = NULL;
2600      }
2601    elm_smart_scroller_region_bring_in(it->wd->scr,
2602                                       it->x + it->block->x,
2603                                       it->y + it->block->y,
2604                                       it->block->w, it->h);
2605 }
2606
2607 /**
2608  * Show the given item at the top
2609  *
2610  * This causes genlist to jump to the given item @p it and show it (by scrolling),
2611  * if it is not fully visible.
2612  *
2613  * @param it The item
2614  *
2615  * @ingroup Genlist
2616  */
2617 EAPI void
2618 elm_genlist_item_top_show(Elm_Genlist_Item *it)
2619 {
2620    Evas_Coord ow, oh;
2621
2622    if (!it) return;
2623    if (it->delete_me) return;
2624    if ((it->queued) || (!it->mincalcd))
2625      {
2626         it->wd->show_item = it;
2627         it->wd->bring_in = 1;
2628         it->showme = EINA_TRUE;
2629         return;
2630      }
2631    if (it->wd->show_item)
2632      {
2633         it->wd->show_item->showme = EINA_FALSE;
2634         it->wd->show_item = NULL;
2635      }
2636    evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh);
2637    elm_smart_scroller_child_region_show(it->wd->scr,
2638                                         it->x + it->block->x,
2639                                         it->y + it->block->y,
2640                                         it->block->w, oh);
2641 }
2642
2643 /**
2644  * Bring in the given item at the top
2645  *
2646  * This causes genlist to jump to the given item @p it and show it (by scrolling),
2647  * if it is not fully visible. This may use animation to do so and take a
2648  * period of time
2649  *
2650  * @param it The item
2651  *
2652  * @ingroup Genlist
2653  */
2654 EAPI void
2655 elm_genlist_item_top_bring_in(Elm_Genlist_Item *it)
2656 {
2657    Evas_Coord ow, oh;
2658
2659    if (!it) return;
2660    if (it->delete_me) return;
2661    if ((it->queued) || (!it->mincalcd))
2662      {
2663         it->wd->show_item = it;
2664         it->wd->bring_in = 1;
2665         it->showme = EINA_TRUE;
2666         return;
2667      }
2668    if (it->wd->show_item)
2669      {
2670         it->wd->show_item->showme = EINA_FALSE;
2671         it->wd->show_item = NULL;
2672      }
2673    evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh);
2674    elm_smart_scroller_region_bring_in(it->wd->scr,
2675                                       it->x + it->block->x,
2676                                       it->y + it->block->y,
2677                                       it->block->w, oh);
2678 }
2679
2680 /**
2681  * Show the given item at the middle
2682  *
2683  * This causes genlist to jump to the given item @p it and show it (by scrolling),
2684  * if it is not fully visible.
2685  *
2686  * @param it The item
2687  *
2688  * @ingroup Genlist
2689  */
2690 EAPI void
2691 elm_genlist_item_middle_show(Elm_Genlist_Item *it)
2692 {
2693    Evas_Coord ow, oh;
2694
2695    if (!it) return;
2696    if (it->delete_me) return;
2697    if ((it->queued) || (!it->mincalcd))
2698      {
2699         it->wd->show_item = it;
2700         it->wd->bring_in = 1;
2701         it->showme = EINA_TRUE;
2702         return;
2703      }
2704    if (it->wd->show_item)
2705      {
2706         it->wd->show_item->showme = EINA_FALSE;
2707         it->wd->show_item = NULL;
2708      }
2709    evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh);
2710    elm_smart_scroller_child_region_show(it->wd->scr,
2711                                         it->x + it->block->x,
2712                          it->y + it->block->y - oh/2 + it->h/2,
2713                                         it->block->w, oh);
2714 }
2715
2716
2717 /**
2718  * Bring in the given item at the middle
2719  *
2720  * This causes genlist to jump to the given item @p it and show it (by scrolling),
2721  * if it is not fully visible. This may use animation to do so and take a
2722  * period of time
2723  *
2724  * @param it The item
2725  *
2726  * @ingroup Genlist
2727  */
2728 EAPI void
2729 elm_genlist_item_middle_bring_in(Elm_Genlist_Item *it)
2730 {
2731    Evas_Coord ow, oh;
2732
2733    if (!it) return;
2734    if (it->delete_me) return;
2735    if ((it->queued) || (!it->mincalcd))
2736      {
2737         it->wd->show_item = it;
2738         it->wd->bring_in = 1;
2739         it->showme = EINA_TRUE;
2740         return;
2741      }
2742    if (it->wd->show_item)
2743      {
2744         it->wd->show_item->showme = EINA_FALSE;
2745         it->wd->show_item = NULL;
2746      }
2747    evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh);
2748    elm_smart_scroller_region_bring_in(it->wd->scr,
2749                                       it->x + it->block->x,
2750                                       it->y + it->block->y - oh/2 + it->h/2,
2751                                       it->block->w, oh);
2752 }
2753
2754 /**
2755  * Delete a given item
2756  *
2757  * This deletes the item from genlist and calls the genlist item del class
2758  * callback defined in the item class, if it is set.
2759  *
2760  * @param it The item
2761  *
2762  * @ingroup Genlist
2763  */
2764 EAPI void
2765 elm_genlist_item_del(Elm_Genlist_Item *it)
2766 {
2767    if (!it) return;
2768    if ((it->relcount > 0) || (it->walking > 0))
2769      {
2770         elm_genlist_item_subitems_clear(it);
2771         it->delete_me = EINA_TRUE;
2772         if (it->wd->show_item == it) it->wd->show_item = NULL;
2773         if (it->selected) it->wd->selected = eina_list_remove(it->wd->selected, it);
2774         if (it->block)
2775           {
2776              if (it->realized) _item_unrealize(it);
2777              it->block->changed = EINA_TRUE;
2778              if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
2779              it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
2780           }
2781         if (it->itc->func.del) it->itc->func.del(it->data, it->wd->obj);
2782         return;
2783      }
2784    _item_del(it);
2785 }
2786
2787 /**
2788  * Set the data item from the genlist item
2789  *
2790  * This set the data value passed on the elm_genlist_item_append() and
2791  * related item addition calls. This function will also call
2792  * elm_genlist_item_update() so the item will be updated to reflect the
2793  * new data.
2794  *
2795  * @param it The item
2796  * @param data The new data pointer to set
2797  *
2798  * @ingroup Genlist
2799  */
2800 EAPI void
2801 elm_genlist_item_data_set(Elm_Genlist_Item *it, const void *data)
2802 {
2803    if (!it) return;
2804    it->data = data;
2805    elm_genlist_item_update(it);
2806 }
2807
2808 /**
2809  * Get the data item from the genlist item
2810  *
2811  * This returns the data value passed on the elm_genlist_item_append() and
2812  * related item addition calls.
2813  *
2814  * @param it The item
2815  * @return The data pointer provided when created
2816  *
2817  * @ingroup Genlist
2818  */
2819 EAPI const void *
2820 elm_genlist_item_data_get(const Elm_Genlist_Item *it)
2821 {
2822    if (!it) return NULL;
2823    return it->data;
2824 }
2825
2826 /**
2827  * Get the real evas object of the genlist item
2828  *
2829  * This returns the actual evas object used for the specified genlist item.
2830  * This may be NULL as it may not be created, and ma be deleted at any time
2831  * by genlist. Do not modify this object (move, resize, show, hide etc.) as
2832  * genlist is controlling it. This function is for querying, emitting
2833  * custom signals or hooking lower level callbacks for events. Do not
2834  * delete this object under any circumstances.
2835  *
2836  * @param it The item
2837  * @return The objct pointer
2838  *
2839  * @ingroup Genlist
2840  */
2841 EAPI const Evas_Object *
2842 elm_genlist_item_object_get(const Elm_Genlist_Item *it)
2843 {
2844    if (!it) return NULL;
2845    return it->base;
2846 }
2847
2848 /**
2849  * Update the contents of an item
2850  *
2851  * This updates an item by calling all the item class functions again to get
2852  * the icons, labels and states. Use this when he original item data has
2853  * changed and the changes are desired to be reflected.
2854  *
2855  * @param it The item
2856  *
2857  * @ingroup Genlist
2858  */
2859 EAPI void
2860 elm_genlist_item_update(Elm_Genlist_Item *it)
2861 {
2862    if (!it->block) return;
2863    if (it->delete_me) return;
2864    it->mincalcd = EINA_FALSE;
2865    it->updateme = EINA_TRUE;
2866    it->block->updateme = EINA_TRUE;
2867    if (it->wd->update_job) ecore_job_del(it->wd->update_job);
2868    it->wd->update_job = ecore_job_add(_update_job, it->wd);
2869 }
2870
2871 /**
2872  * This sets the horizontal stretching mode
2873  *
2874  * This sets the mode used for sizing items horizontally. Valid modes are
2875  * ELM_LIST_LIMIT and ELM_LIST_SCROLL. The default is ELM_LIST_SCROLL. This
2876  * mode means that if items are too wide to fit, the scroller will scroll
2877  * horizontally. Otherwise items are expanded to fill the width of the
2878  * viewport of the scroller. If it is ELM_LIST_LIMIT, Items will be expanded
2879  * to the viewport width and limited to that size.
2880  *
2881  * @param obj The genlist object
2882  * @param mode The mode to use
2883  *
2884  * @ingroup Genlist
2885  */
2886 EAPI void
2887 elm_genlist_horizontal_mode_set(Evas_Object *obj, Elm_List_Mode mode)
2888 {
2889    ELM_CHECK_WIDTYPE(obj, widtype);
2890    Widget_Data *wd = elm_widget_data_get(obj);
2891    if (!wd) return;
2892    if (wd->mode == mode) return;
2893    wd->mode = mode;
2894    _sizing_eval(obj);
2895 }
2896
2897 /**
2898  * Gets the horizontal stretching mode
2899  *
2900  * @param obj The genlist object
2901  * @return The mode to use
2902  * (ELM_LIST_LIMIT, ELM_LIST_SCROLL, ELM_LIST_LIMIT)
2903  *
2904  * @ingroup Genlist
2905  */
2906 EAPI Elm_List_Mode
2907 elm_genlist_horizontal_mode_get(const Evas_Object *obj)
2908 {
2909    ELM_CHECK_WIDTYPE(obj, widtype) ELM_LIST_LAST;
2910    Widget_Data *wd = elm_widget_data_get(obj);
2911    if (!wd) return ELM_LIST_LAST;
2912    return wd->mode;
2913 }
2914
2915 /**
2916  * Set the always select mode.
2917  *
2918  * Items will only call their selection func and callback when first becoming
2919  * selected. Any further clicks will do nothing, unless you enable always
2920  * select with elm_genlist_always_select_mode_set(). This means even if
2921  * selected, every click will make the selected callbacks be called.
2922  *
2923  * @param obj The genlist object
2924  * @param always_select The always select mode
2925  * (EINA_TRUE = on, EINA_FALSE = off)
2926  *
2927  * @ingroup Genlist
2928  */
2929 EAPI void
2930 elm_genlist_always_select_mode_set(Evas_Object *obj, Eina_Bool always_select)
2931 {
2932    ELM_CHECK_WIDTYPE(obj, widtype);
2933    Widget_Data *wd = elm_widget_data_get(obj);
2934    if (!wd) return;
2935    wd->always_select = always_select;
2936 }
2937
2938 /**
2939  * Get the always select mode.
2940  *
2941  * @param obj The genlist object
2942  * @return The always select mode
2943  * (EINA_TRUE = on, EINA_FALSE = off)
2944  *
2945  * @ingroup Genlist
2946  */
2947 EAPI Eina_Bool
2948 elm_genlist_always_select_mode_get(const Evas_Object *obj)
2949 {
2950    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2951    Widget_Data *wd = elm_widget_data_get(obj);
2952    if (!wd) return EINA_FALSE;
2953    return wd->always_select;
2954 }
2955
2956 /**
2957  * Set no select mode
2958  *
2959  * This will turn off the ability to select items entirely and they will
2960  * neither appear selected nor call selected callback functions.
2961  *
2962  * @param obj The genlist object
2963  * @param no_select The no select mode
2964  * (EINA_TRUE = on, EINA_FALSE = off)
2965  *
2966  * @ingroup Genlist
2967  */
2968 EAPI void
2969 elm_genlist_no_select_mode_set(Evas_Object *obj, Eina_Bool no_select)
2970 {
2971    ELM_CHECK_WIDTYPE(obj, widtype);
2972    Widget_Data *wd = elm_widget_data_get(obj);
2973    if (!wd) return;
2974    wd->no_select = no_select;
2975 }
2976
2977 /**
2978  * Gets no select mode
2979  *
2980  * @param obj The genlist object
2981  * @return The no select mode
2982  * (EINA_TRUE = on, EINA_FALSE = off)
2983  *
2984  * @ingroup Genlist
2985  */
2986 EAPI Eina_Bool
2987 elm_genlist_no_select_mode_get(const Evas_Object *obj)
2988 {
2989    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2990    Widget_Data *wd = elm_widget_data_get(obj);
2991    if (!wd) return EINA_FALSE;
2992    return wd->no_select;
2993 }
2994
2995 /**
2996  * Set compress mode
2997  *
2998  * This will enable the compress mode where items are "compressed" horizontally
2999  * to fit the genlist scrollable viewport width.
3000  *
3001  * @param obj The genlist object
3002  * @param no_select The compress mode
3003  * (EINA_TRUE = on, EINA_FALSE = off)
3004  *
3005  * @ingroup Genlist
3006  */
3007 EAPI void
3008 elm_genlist_compress_mode_set(Evas_Object *obj, Eina_Bool compress)
3009 {
3010    ELM_CHECK_WIDTYPE(obj, widtype);
3011    Widget_Data *wd = elm_widget_data_get(obj);
3012    if (!wd) return;
3013    wd->compress = compress;
3014 }
3015
3016 /**
3017  * Get the compress mode
3018  *
3019  * @param obj The genlist object
3020  * @return The compress mode
3021  * (EINA_TRUE = on, EINA_FALSE = off)
3022  *
3023  * @ingroup Genlist
3024  */
3025 EAPI Eina_Bool
3026 elm_genlist_compress_mode_get(const Evas_Object *obj)
3027 {
3028    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
3029    Widget_Data *wd = elm_widget_data_get(obj);
3030    if (!wd) return EINA_FALSE;
3031    return wd->compress;
3032 }
3033
3034 /**
3035  * Set bounce mode
3036  *
3037  * This will enable or disable the scroller bounce mode for the genlist. See 
3038  * elm_scroller_bounce_set() for details
3039  *
3040  * @param obj The genlist object
3041  * @param h_bounce Allow bounce horizontally
3042  * @param v_bounce Allow bounce vertically
3043  *
3044  * @ingroup Genlist
3045  */
3046 EAPI void
3047 elm_genlist_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce)
3048 {
3049    ELM_CHECK_WIDTYPE(obj, widtype);
3050    Widget_Data *wd = elm_widget_data_get(obj);
3051    if (!wd) return;
3052    elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
3053 }
3054
3055 /**
3056  * Get the bounce mode
3057  *
3058  * @param obj The genlist object
3059  * @param h_bounce Allow bounce horizontally
3060  * @param v_bounce Allow bounce vertically
3061  *
3062  * @ingroup Genlist
3063  */
3064 EAPI void
3065 elm_genlist_bounce_get(const Evas_Object *obj, Eina_Bool *h_bounce, Eina_Bool *v_bounce)
3066 {
3067    ELM_CHECK_WIDTYPE(obj, widtype);
3068    Widget_Data *wd = elm_widget_data_get(obj);
3069    if (!wd) return;
3070    elm_smart_scroller_bounce_allow_get(obj, h_bounce, v_bounce);
3071 }
3072
3073 /**
3074  * Set homogenous mode
3075  *
3076  * This will enable the homogeneous mode where items are of the same height and width
3077  * so that genlist may do the lazy-loading at its maximum.  This implies 'compressed' mode
3078  *
3079  * @param obj The genlist object
3080  * @param homogeneous Assume the items within the genlist are of the same height and width
3081  * (EINA_TRUE = on, EINA_FALSE = off)
3082  *
3083  * @ingroup Genlist
3084  */
3085 EAPI void
3086 elm_genlist_homogeneous_set(Evas_Object *obj, Eina_Bool homogeneous)
3087 {
3088    ELM_CHECK_WIDTYPE(obj, widtype);
3089    Widget_Data *wd = elm_widget_data_get(obj);
3090    if (!wd) return;
3091    if (homogeneous) elm_genlist_compress_mode_set(obj, EINA_TRUE);
3092    wd->homogeneous = homogeneous;
3093 }
3094
3095 /**
3096  * Get the homogenous mode
3097  *
3098  * @param obj The genlist object
3099  * @return Assume the items within the genlist are of the same height and width
3100  * (EINA_TRUE = on, EINA_FALSE = off)
3101  *
3102  * @ingroup Genlist
3103  */
3104 EAPI Eina_Bool
3105 elm_genlist_homogeneous_get(const Evas_Object *obj)
3106 {
3107    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
3108    Widget_Data *wd = elm_widget_data_get(obj);
3109    if (!wd) return EINA_FALSE;
3110    return wd->homogeneous;
3111 }
3112
3113 /**
3114  * Set the maximum number of items within an item block
3115  *
3116  * This will configure the block count to tune to the target with particular performance matrix.
3117  *
3118  * @param obj The genlist object
3119  * @param n   Maximum number of items within an item block
3120  *
3121  * @ingroup Genlist
3122  */
3123 EAPI void
3124 elm_genlist_block_count_set(Evas_Object *obj, int n)
3125 {
3126    ELM_CHECK_WIDTYPE(obj, widtype);
3127    Widget_Data *wd = elm_widget_data_get(obj);
3128    if (!wd) return;
3129    wd->max_items_per_block = n;
3130 }
3131
3132 /**
3133  * Get the maximum number of items within an item block
3134  *
3135  * @param obj The genlist object
3136  * @return Maximum number of items within an item block
3137  *
3138  * @ingroup Genlist
3139  */
3140 EAPI int
3141 elm_genlist_block_count_get(const Evas_Object *obj)
3142 {
3143    ELM_CHECK_WIDTYPE(obj, widtype) 0;
3144    Widget_Data *wd = elm_widget_data_get(obj);
3145    if (!wd) return 0;
3146    return wd->max_items_per_block;
3147 }