[elm_genlist.c] change rename mode name and api return value
[framework/uifw/elementary.git] / src / lib / elm_genlist.c
1 #include <Elementary.h>
2 #include <Elementary_Cursor.h>
3 #include "elm_priv.h"
4
5 #define SWIPE_MOVES         12
6 #define MAX_ITEMS_PER_BLOCK 32
7
8 /**
9  * @defgroup Genlist Genlist
10  *
11  * The aim was to have more expansive list than 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  * complex 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  * unrealized - This is called just before an item is unrealized. After
58  * this call icon objects provided will be deleted and the item object
59  * itself delete or be put into a floating cache.
60  *
61  * drag,start,up - This is called when the item in the list has been dragged
62  * (not scrolled) up.
63  *
64  * drag,start,down - This is called when the item in the list has been dragged
65  * (not scrolled) down.
66  *
67  * drag,start,left - This is called when the item in the list has been dragged
68  * (not scrolled) left.
69  *
70  * drag,start,right - This is called when the item in the list has been dragged
71  * (not scrolled) right.
72  *
73  * drag,stop - This is called when the item in the list has stopped being
74  * dragged.
75  *
76  * drag - This is called when the item in the list is being dragged.
77  *
78  * longpressed - This is called when the item is pressed for a certain amount
79  * of time. By default it's 1 second.
80  *
81  * scroll,edge,top - This is called when the genlist is scrolled until the top
82  * edge.
83  *
84  * scroll,edge,bottom - This is called when the genlist is scrolled until the
85  * bottom edge.
86  *
87  * scroll,edge,left - This is called when the genlist is scrolled until the
88  * left edge.
89  *
90  * scroll,edge,right - This is called when the genlist is scrolled until the
91  * right edge.
92  *
93  * multi,swipe,left - This is called when the genlist is multi-touch swiped
94  * left.
95  *
96  * multi,swipe,right - This is called when the genlist is multi-touch swiped
97  * right.
98  *
99  * multi,swipe,up - This is called when the genlist is multi-touch swiped
100  * up.
101  *
102  * multi,swipe,down - This is called when the genlist is multi-touch swiped
103  * down.
104  *
105  * multi,pinch,out - This is called when the genlist is multi-touch pinched
106  * out.
107  *
108  * multi,pinch,in - This is called when the genlist is multi-touch pinched
109  * in.
110  *
111  * Genlist has a fairly large API, mostly because it's relatively complex,
112  * trying to be both expansive, powerful and efficient. First we will begin
113  * an overview on the theory behind genlist.
114  *
115  * Evas tracks every object you create. Every time it processes an event
116  * (mouse move, down, up etc.) it needs to walk through objects and find out
117  * what event that affects. Even worse every time it renders display updates,
118  * in order to just calculate what to re-draw, it needs to walk through many
119  * many many objects. Thus, the more objects you keep active, the more
120  * overhead Evas has in just doing its work. It is advisable to keep your
121  * active objects to the minimum working set you need. Also remember that
122  * object creation and deletion carries an overhead, so there is a
123  * middle-ground, which is not easily determined. But don't keep massive lists
124  * of objects you can't see or use. Genlist does this with list objects. It
125  * creates and destroys them dynamically as you scroll around. It groups them
126  * into blocks so it can determine the visibility etc. of a whole block at
127  * once as opposed to having to walk the whole list. This 2-level list allows
128  * for very large numbers of items to be in the list (tests have used up to
129  * 2,000,000 items). Also genlist employs a queue for adding items. As items
130  * may be different sizes, every item added needs to be calculated as to its
131  * size and thus this presents a lot of overhead on populating the list, this
132  * genlist employs a queue. Any item added is queued and spooled off over
133  * time, actually appearing some time later, so if your list has many members
134  * you may find it takes a while for them to all appear, with your process
135  * consuming a lot of CPU while it is busy spooling.
136  *
137  * Genlist also implements a tree structure, but it does so with callbacks to
138  * the application, with the application filling in tree structures when
139  * requested (allowing for efficient building of a very deep tree that could
140  * even be used for file-management). See the above smart signal callbacks for
141  * details.
142  *
143  * An item in the genlist world can have 0 or more text labels (they can be
144  * regular text or textblock - that's up to the style to determine), 0 or
145  * more icons (which are simply objects swallowed into the genlist item) and
146  * 0 or more boolean states that can be used for check, radio or other
147  * indicators by the edje theme style. An item may be one of several styles
148  * (Elementary provides 4 by default - "default", "double_label", "group_index"
149  * and "icon_top_text_bottom", but this can be extended by system or
150  * application custom themes/overlays/extensions).
151  *
152  * In order to implement the ability to add and delete items on the fly,
153  * Genlist implements a class/callback system where the application provides
154  * a structure with information about that type of item (genlist may contain
155  * multiple different items with different classes, states and styles).
156  * Genlist will call the functions in this struct (methods) when an item is
157  * "realized" (that is created dynamically while scrolling). All objects will
158  * simply be deleted  when no longer needed with evas_object_del(). The
159  * Elm_Genlist_Item_Class structure contains the following members:
160  *
161  * item_style - This is a constant string and simply defines the name of the
162  * item style. It must be specified and the default should be "default".
163  *
164  * func.label_get - This function is called when an actual item object is
165  * created. The data parameter is the data parameter passed to
166  * elm_genlist_item_append() and related item creation functions. The obj
167  * parameter is the genlist object and the part parameter is the string name
168  * of the text part in the edje design that is listed as one of the possible
169  * labels that can be set. This function must return a strudup()'ed string as
170  * the caller will free() it when done.
171  *
172  * func.icon_get - This function is called when an actual item object is
173  * created. The data parameter is the data parameter passed to
174  * elm_genlist_item_append() and related item creation functions. The obj
175  * parameter is the genlist object and the part parameter is the string name
176  * of the icon part in the edje design that is listed as one of the possible
177  * icons that can be set. This must return NULL for no object or a valid
178  * object. The object will be deleted by genlist on shutdown or when the item
179  * is unrealized.
180  *
181  * func.state_get - This function is called when an actual item object is
182  * created. The data parameter is the data parameter passed to
183  * elm_genlist_item_append() and related item creation functions. The obj
184  * parameter is the genlist object and the part parameter is the string name
185  * of the state part in the edje design that is listed as one of the possible
186  * states that can be set. Return 0 for false or 1 for true. Genlist will
187  * emit a signal to the edje object with "elm,state,XXX,active" "elm" when
188  * true (the default is false), where XXX is the name of the part.
189  *
190  * func.del - This is called when elm_genlist_item_del() is called on an
191  * item, elm_genlist_clear() is called on the genlist, or
192  * elm_genlist_item_subitems_clear() is called to clear sub-items. This is
193  * intended for use when actual genlist items are deleted, so any backing
194  * data attached to the item (e.g. its data parameter on creation) can be
195  * deleted.
196  *
197  * Items can be added by several calls. All of them return a Elm_Genlist_Item
198  * handle that is an internal member inside the genlist. They all take a data
199  * parameter that is meant to be used for a handle to the applications
200  * internal data (eg the struct with the original item data). The parent
201  * parameter is the parent genlist item this belongs to if it is a tree or
202  * an indexed group, and NULL if there is no parent. The flags can be a bitmask
203  * of ELM_GENLIST_ITEM_NONE, ELM_GENLIST_ITEM_SUBITEMS and
204  * ELM_GENLIST_ITEM_GROUP. If ELM_GENLIST_ITEM_SUBITEMS is set then this item
205  * is displayed as an item that is able to expand and have child items.
206  * If ELM_GENLIST_ITEM_GROUP is set then this item is group idex item that is
207  * displayed at the top until the next group comes. The func parameter is a
208  * convenience callback that is called when the item is selected and the data
209  * parameter will be the func_data parameter, obj be the genlist object and
210  * event_info will be the genlist item.
211  *
212  * elm_genlist_item_append() appends an item to the end of the list, or if
213  * there is a parent, to the end of all the child items of the parent.
214  * elm_genlist_item_prepend() is the same but prepends to the beginning of
215  * the list or children list. elm_genlist_item_insert_before() inserts at
216  * item before another item and elm_genlist_item_insert_after() inserts after
217  * the indicated item.
218  *
219  * The application can clear the list with elm_genlist_clear() which deletes
220  * all the items in the list and elm_genlist_item_del() will delete a specific
221  * item. elm_genlist_item_subitems_clear() will clear all items that are
222  * children of the indicated parent item.
223  *
224  * If the application wants multiple items to be able to be selected,
225  * elm_genlist_multi_select_set() can enable this. If the list is
226  * single-selection only (the default), then elm_genlist_selected_item_get()
227  * will return the selected item, if any, or NULL I none is selected. If the
228  * list is multi-select then elm_genlist_selected_items_get() will return a
229  * list (that is only valid as long as no items are modified (added, deleted,
230  * selected or unselected)).
231  *
232  * To help inspect list items you can jump to the item at the top of the list
233  * with elm_genlist_first_item_get() which will return the item pointer, and
234  * similarly elm_genlist_last_item_get() gets the item at the end of the list.
235  * elm_genlist_item_next_get() and elm_genlist_item_prev_get() get the next
236  * and previous items respectively relative to the indicated item. Using
237  * these calls you can walk the entire item list/tree. Note that as a tree
238  * the items are flattened in the list, so elm_genlist_item_parent_get() will
239  * let you know which item is the parent (and thus know how to skip them if
240  * wanted).
241  *
242  * There are also convenience functions. elm_genlist_item_genlist_get() will
243  * return the genlist object the item belongs to. elm_genlist_item_show()
244  * will make the scroller scroll to show that specific item so its visible.
245  * elm_genlist_item_data_get() returns the data pointer set by the item
246  * creation functions.
247  *
248  * If an item changes (state of boolean changes, label or icons change),
249  * then use elm_genlist_item_update() to have genlist update the item with
250  * the new state. Genlist will re-realize the item thus call the functions
251  * in the _Elm_Genlist_Item_Class for that item.
252  *
253  * To programmatically (un)select an item use elm_genlist_item_selected_set().
254  * To get its selected state use elm_genlist_item_selected_get(). Similarly
255  * to expand/contract an item and get its expanded state, use
256  * elm_genlist_item_expanded_set() and elm_genlist_item_expanded_get(). And
257  * again to make an item disabled (unable to be selected and appear
258  * differently) use elm_genlist_item_disabled_set() to set this and
259  * elm_genlist_item_disabled_get() to get the disabled state.
260  *
261  * In general to indicate how the genlist should expand items horizontally to
262  * fill the list area, use elm_genlist_horizontal_mode_set(). Valid modes are
263  * ELM_LIST_LIMIT and ELM_LIST_SCROLL . The default is ELM_LIST_SCROLL. This
264  * mode means that if items are too wide to fit, the scroller will scroll
265  * horizontally. Otherwise items are expanded to fill the width of the
266  * viewport of the scroller. If it is ELM_LIST_LIMIT, items will be expanded
267  * to the viewport width and limited to that size. This can be combined with
268  * a different style that uses edjes' ellipsis feature (cutting text off like
269  * this: "tex...").
270  *
271  * Items will only call their selection func and callback when first becoming
272  * selected. Any further clicks will do nothing, unless you enable always
273  * select with elm_genlist_always_select_mode_set(). This means even if
274  * selected, every click will make the selected callbacks be called.
275  * elm_genlist_no_select_mode_set() will turn off the ability to select
276  * items entirely and they will neither appear selected nor call selected
277  * callback functions.
278  *
279  * Remember that you can create new styles and add your own theme augmentation
280  * per application with elm_theme_extension_add(). If you absolutely must
281  * have a specific style that overrides any theme the user or system sets up
282  * you can use elm_theme_overlay_add() to add such a file.
283  */
284
285 typedef struct _Widget_Data Widget_Data;
286 typedef struct _Item_Block  Item_Block;
287 typedef struct _Pan         Pan;
288 typedef struct _Item_Cache  Item_Cache;
289 typedef struct _Edit_Data Edit_Data;
290
291 typedef enum _Elm_Genlist_Item_Move_effect_Mode
292 {
293    ELM_GENLIST_ITEM_MOVE_EFFECT_NONE         = 0,
294    ELM_GENLIST_ITEM_MOVE_EFFECT_EXPAND       = (1 << 0),
295    ELM_GENLIST_ITEM_MOVE_EFFECT_CONTRACT     = (1 << 1),
296    ELM_GENLIST_ITEM_MOVE_EFFECT_EDIT_MODE    = (1 << 2),
297    ELM_GENLIST_ITEM_MOVE_EFFECT_DELETE       = (1 << 3),
298 } Elm_Genlist_Item_Move_effect_Mode;
299
300 struct _Widget_Data
301 {
302    Evas_Object      *obj, *scr, *pan_smart;
303    Eina_Inlist      *items, *blocks;
304    Eina_List        *group_items;
305    Pan              *pan;
306    Evas_Coord        pan_x, pan_y, w, h, minw, minh, realminw, prev_viewport_w;
307    Ecore_Job        *calc_job, *update_job;
308    Ecore_Idler      *queue_idler;
309    Ecore_Idler      *must_recalc_idler;
310    Eina_List        *queue, *selected;
311    Elm_Genlist_Item *show_item;
312    Elm_Genlist_Item *last_selected_item;
313    Eina_Inlist      *item_cache;
314    Elm_Genlist_Item *anchor_item;
315    Evas_Coord        anchor_y;
316    Elm_List_Mode     mode;
317    Ecore_Timer      *multi_timer;
318    Evas_Coord        prev_x, prev_y, prev_mx, prev_my;
319    Evas_Coord        cur_x, cur_y, cur_mx, cur_my;
320    Eina_Bool         mouse_down : 1;
321    Eina_Bool         multi_down : 1;
322    Eina_Bool         multi_timeout : 1;
323    Eina_Bool         multitouched : 1;
324    Eina_Bool         on_hold : 1;
325    Eina_Bool         multi : 1;
326    Eina_Bool         always_select : 1;
327    Eina_Bool         longpressed : 1;
328    Eina_Bool         wasselected : 1;
329    Eina_Bool         no_select : 1;
330    Eina_Bool         bring_in : 1;
331    Eina_Bool         compress : 1;
332    Eina_Bool         height_for_width : 1;
333    Eina_Bool         homogeneous : 1;
334    Eina_Bool         clear_me : 1;
335    Eina_Bool         swipe : 1;
336    struct
337    {
338       Evas_Coord x, y;
339    } history[SWIPE_MOVES];
340    int               multi_device;
341    int               item_cache_count;
342    int               item_cache_max;
343    int               movements;
344    int               walking;
345    int               item_width;
346    int               item_height;
347    int               group_item_width;
348    int               group_item_height;
349    int               max_items_per_block;
350    double            longpress_timeout;
351
352    // TODO : refactoring
353    Eina_Bool         reorder_mode : 1;
354    Eina_Bool         reorder_pan_move : 1;
355    Eina_Bool         reorder_deleted : 1;
356    Eina_Bool         effect_mode : 1;
357    Eina_Bool         auto_scrolled : 1;
358    Eina_Bool         contracting : 1;
359    int               edit_mode;
360    Eina_List        *sweeped_items;
361    Ecore_Timer      *scr_hold_timer;
362    int               total_num;
363    Elm_Genlist_Item *reorder_it, *reorder_rel;
364    Evas_Coord        reorder_start_y;
365    Ecore_Animator   *item_moving_effect_timer;
366    Evas_Object      *alpha_bg;
367    Elm_Genlist_Item *expand_item;
368    Evas_Coord        expand_item_end;
369    Evas_Coord        expand_item_gap;
370    int               move_effect_mode;
371    unsigned int      start_time;
372    Ecore_Job        *changed_job;
373    Elm_Genlist_Item *rename_it;
374 };
375
376 struct _Item_Block
377 {
378    EINA_INLIST;
379    int          count;
380    int          num;
381    Widget_Data *wd;
382    Eina_List   *items;
383    Evas_Coord   x, y, w, h, minw, minh;
384    Eina_Bool    want_unrealize : 1;
385    Eina_Bool    realized : 1;
386    Eina_Bool    changed : 1;
387    Eina_Bool    updateme : 1;
388    Eina_Bool    showme : 1;
389    Eina_Bool    must_recalc : 1;
390    int          reorder_offset;
391 };
392
393 struct _Elm_Genlist_Item
394 {
395    Elm_Widget_Item               base;
396    EINA_INLIST;
397    Widget_Data                  *wd;
398    Item_Block                   *block;
399    Eina_List                    *items;
400    Evas_Coord                    x, y, w, h, minw, minh;
401    const Elm_Genlist_Item_Class *itc;
402    Elm_Genlist_Item             *parent;
403    Elm_Genlist_Item             *group_item;
404    Elm_Genlist_Item_Flags        flags;
405    struct
406    {
407       Evas_Smart_Cb func;
408       const void   *data;
409    } func;
410
411    Evas_Object      *spacer;
412    Eina_List        *labels, *icons, *states, *icon_objs;
413    Ecore_Timer      *long_timer;
414    Ecore_Timer      *swipe_timer;
415    Evas_Coord        dx, dy;
416    Evas_Coord        scrl_x, scrl_y;
417
418    Elm_Genlist_Item *rel;
419
420    struct
421    {
422       const void                 *data;
423       Elm_Tooltip_Item_Content_Cb content_cb;
424       Evas_Smart_Cb               del_cb;
425       const char                 *style;
426    } tooltip;
427
428    const char *mouse_cursor;
429
430    int         relcount;
431    int         walking;
432    int         expanded_depth;
433    int         order_num_in;
434
435    Eina_Bool   before : 1;
436
437    Eina_Bool   want_unrealize : 1;
438    Eina_Bool   want_realize : 1;
439    Eina_Bool   realized : 1;
440    Eina_Bool   selected : 1;
441    Eina_Bool   highlighted : 1;
442    Eina_Bool   expanded : 1;
443    Eina_Bool   disabled : 1;
444    Eina_Bool   display_only : 1;
445    Eina_Bool   mincalcd : 1;
446    Eina_Bool   queued : 1;
447    Eina_Bool   showme : 1;
448    Eina_Bool   delete_me : 1;
449    Eina_Bool   down : 1;
450    Eina_Bool   dragging : 1;
451    Eina_Bool   updateme : 1;
452    Eina_Bool   nocache : 1;
453
454    // TODO: refactoring
455    Eina_Bool   move_effect_me : 1;
456    Eina_Bool   effect_done : 1;
457    Eina_Bool   reordering : 1;
458    Eina_Bool   renamed : 1;
459    Eina_Bool   effect_item_realized : 1;
460    Eina_Bool   sweeped : 1;
461    Eina_Bool   wassweeped : 1;
462    Eina_List  *edit_icon_objs;
463    Evas_Object *edit_obj;
464    Eina_List  *sweep_labels, *sweep_icons, *sweep_icon_objs;
465    int         num;
466    Ecore_Animator *item_moving_effect_timer;
467    Evas_Coord  old_scrl_x, old_scrl_y;
468 };
469
470 struct _Item_Cache
471 {
472    EINA_INLIST;
473
474    Evas_Object *base_view, *spacer;
475
476    const char  *item_style; // it->itc->item_style
477    Eina_Bool    tree : 1; // it->flags & ELM_GENLIST_ITEM_SUBITEMS
478    Eina_Bool    compress : 1; // it->wd->compress
479    Eina_Bool    odd : 1; // in & 0x1
480
481    Eina_Bool    selected : 1; // it->selected
482    Eina_Bool    disabled : 1; // it->disabled
483    Eina_Bool    expanded : 1; // it->expanded
484 };
485
486 #define ELM_GENLIST_ITEM_FROM_INLIST(item) \
487   ((item) ? EINA_INLIST_CONTAINER_GET(item, Elm_Genlist_Item) : NULL)
488
489 struct _Pan
490 {
491    Evas_Object_Smart_Clipped_Data __clipped_data;
492    Widget_Data                   *wd;
493    Ecore_Job                     *resize_job;
494 };
495
496 static const char *widtype = NULL;
497 static void      _item_cache_zero(Widget_Data *wd);
498 static void      _del_hook(Evas_Object *obj);
499 static void      _mirrored_set(Evas_Object *obj,
500                                Eina_Bool    rtl);
501 static void      _theme_hook(Evas_Object *obj);
502 static void      _show_region_hook(void        *data,
503                                    Evas_Object *obj);
504 static void      _sizing_eval(Evas_Object *obj);
505 static void      _item_unrealize(Elm_Genlist_Item *it);
506 static void      _item_block_unrealize(Item_Block *itb);
507 static void      _calc_job(void *data);
508 static void      _on_focus_hook(void        *data,
509                                 Evas_Object *obj);
510 static void      _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
511 static void      _changed_job(void *data);
512 static Eina_Bool _item_multi_select_up(Widget_Data *wd);
513 static Eina_Bool _item_multi_select_down(Widget_Data *wd);
514 static Eina_Bool _item_single_select_up(Widget_Data *wd);
515 static Eina_Bool _item_single_select_down(Widget_Data *wd);
516 static Eina_Bool _event_hook(Evas_Object       *obj,
517                              Evas_Object       *src,
518                              Evas_Callback_Type type,
519                              void              *event_info);
520 static Eina_Bool _deselect_all_items(Widget_Data *wd);
521 static void      _pan_calculate(Evas_Object *obj);
522 // TODO : refactoring
523 static Evas_Object* _create_tray_alpha_bg(const Evas_Object *obj);
524 static unsigned int current_time_get();
525 static Eina_Bool _item_moving_effect_timer_cb(void *data);
526 static int _item_flip_effect_show(Elm_Genlist_Item *it);
527 static void _effect_item_controls(Elm_Genlist_Item *it, int itx, int ity);
528 static void _effect_item_realize(Elm_Genlist_Item *it, Eina_Bool effect_on);
529 static void _effect_item_unrealize(Elm_Genlist_Item *it);
530 static void _item_slide(Elm_Genlist_Item *it, Eina_Bool slide_to_right);
531 static void _sweep_finish(void *data, Evas_Object *o, const char *emission, const char *source);
532 static void _create_sweep_objs(Elm_Genlist_Item *it);
533 static void _delete_sweep_objs(Elm_Genlist_Item *it);
534 static void _effect_item_move_after(Elm_Genlist_Item *it, Elm_Genlist_Item *after);
535 static void _effect_item_move_before(Elm_Genlist_Item *it, Elm_Genlist_Item *before);
536 static void _group_items_recalc(void *data);
537 static void _item_auto_scroll(void *data);
538
539 static Evas_Smart_Class _pan_sc = EVAS_SMART_CLASS_INIT_VERSION;
540
541 static Eina_Bool
542 _event_hook(Evas_Object       *obj,
543             Evas_Object *src   __UNUSED__,
544             Evas_Callback_Type type,
545             void              *event_info)
546 {
547    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
548    Evas_Event_Key_Down *ev = event_info;
549    Widget_Data *wd = elm_widget_data_get(obj);
550    if (!wd) return EINA_FALSE;
551    if (!wd->items) return EINA_FALSE;
552    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
553    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
554
555    Elm_Genlist_Item *it = NULL;
556    Evas_Coord x = 0;
557    Evas_Coord y = 0;
558    Evas_Coord step_x = 0;
559    Evas_Coord step_y = 0;
560    Evas_Coord v_w = 0;
561    Evas_Coord v_h = 0;
562    Evas_Coord page_x = 0;
563    Evas_Coord page_y = 0;
564
565    elm_smart_scroller_child_pos_get(wd->scr, &x, &y);
566    elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y);
567    elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y);
568    elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h);
569
570    if ((!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left")))
571      {
572         x -= step_x;
573      }
574    else if ((!strcmp(ev->keyname, "Right")) ||
575             (!strcmp(ev->keyname, "KP_Right")))
576      {
577         x += step_x;
578      }
579    else if ((!strcmp(ev->keyname, "Up")) || (!strcmp(ev->keyname, "KP_Up")))
580      {
581         if (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
582              (_item_multi_select_up(wd)))
583             || (_item_single_select_up(wd)))
584           {
585              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
586              return EINA_TRUE;
587           }
588         else
589           y -= step_y;
590      }
591    else if ((!strcmp(ev->keyname, "Down")) || (!strcmp(ev->keyname, "KP_Down")))
592      {
593         if (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
594              (_item_multi_select_down(wd)))
595             || (_item_single_select_down(wd)))
596           {
597              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
598              return EINA_TRUE;
599           }
600         else
601           y += step_y;
602      }
603    else if ((!strcmp(ev->keyname, "Home")) ||
604             (!strcmp(ev->keyname, "KP_Home")))
605      {
606         it = elm_genlist_first_item_get(obj);
607         elm_genlist_item_bring_in(it);
608         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
609         return EINA_TRUE;
610      }
611    else if ((!strcmp(ev->keyname, "End")) ||
612             (!strcmp(ev->keyname, "KP_End")))
613      {
614         it = elm_genlist_last_item_get(obj);
615         elm_genlist_item_bring_in(it);
616         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
617         return EINA_TRUE;
618      }
619    else if ((!strcmp(ev->keyname, "Prior")) ||
620             (!strcmp(ev->keyname, "KP_Prior")))
621      {
622         if (page_y < 0)
623           y -= -(page_y * v_h) / 100;
624         else
625           y -= page_y;
626      }
627    else if ((!strcmp(ev->keyname, "Next")) ||
628             (!strcmp(ev->keyname, "KP_Next")))
629      {
630         if (page_y < 0)
631           y += -(page_y * v_h) / 100;
632         else
633           y += page_y;
634      }
635    else if(((!strcmp(ev->keyname, "Return")) ||
636             (!strcmp(ev->keyname, "KP_Enter")) ||
637             (!strcmp(ev->keyname, "space")))
638            && (!wd->multi) && (wd->selected))
639      {
640         Elm_Genlist_Item *it = elm_genlist_selected_item_get(obj);
641         elm_genlist_item_expanded_set(it,
642                                       !elm_genlist_item_expanded_get(it));
643      }
644    else if (!strcmp(ev->keyname, "Escape"))
645      {
646         if (!_deselect_all_items(wd)) return EINA_FALSE;
647         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
648         return EINA_TRUE;
649      }
650    else return EINA_FALSE;
651
652    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
653    elm_smart_scroller_child_pos_set(wd->scr, x, y);
654    return EINA_TRUE;
655 }
656
657 static Eina_Bool
658 _deselect_all_items(Widget_Data *wd)
659 {
660    if (!wd->selected) return EINA_FALSE;
661    while(wd->selected)
662      elm_genlist_item_selected_set(wd->selected->data, EINA_FALSE);
663
664    return EINA_TRUE;
665 }
666
667 static Eina_Bool
668 _item_multi_select_up(Widget_Data *wd)
669 {
670    if (!wd->selected) return EINA_FALSE;
671    if (!wd->multi) return EINA_FALSE;
672
673    Elm_Genlist_Item *prev = elm_genlist_item_prev_get(wd->last_selected_item);
674    if (!prev) return EINA_TRUE;
675
676    if (elm_genlist_item_selected_get(prev))
677      {
678         elm_genlist_item_selected_set(wd->last_selected_item, EINA_FALSE);
679         wd->last_selected_item = prev;
680         elm_genlist_item_show(wd->last_selected_item);
681      }
682    else
683      {
684         elm_genlist_item_selected_set(prev, EINA_TRUE);
685         elm_genlist_item_show(prev);
686      }
687    return EINA_TRUE;
688 }
689
690 static Eina_Bool
691 _item_multi_select_down(Widget_Data *wd)
692 {
693    if (!wd->selected) return EINA_FALSE;
694    if (!wd->multi) return EINA_FALSE;
695
696    Elm_Genlist_Item *next = elm_genlist_item_next_get(wd->last_selected_item);
697    if (!next) return EINA_TRUE;
698
699    if (elm_genlist_item_selected_get(next))
700      {
701         elm_genlist_item_selected_set(wd->last_selected_item, EINA_FALSE);
702         wd->last_selected_item = next;
703         elm_genlist_item_show(wd->last_selected_item);
704      }
705    else
706      {
707         elm_genlist_item_selected_set(next, EINA_TRUE);
708         elm_genlist_item_show(next);
709      }
710    return EINA_TRUE;
711 }
712
713 static Eina_Bool
714 _item_single_select_up(Widget_Data *wd)
715 {
716    Elm_Genlist_Item *prev;
717    if (!wd->selected)
718      {
719         prev = ELM_GENLIST_ITEM_FROM_INLIST(wd->items->last);
720         while ((prev) && (prev->delete_me))
721           prev = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(prev)->prev);
722      }
723    else prev = elm_genlist_item_prev_get(wd->last_selected_item);
724
725    if (!prev) return EINA_FALSE;
726
727    _deselect_all_items(wd);
728
729    elm_genlist_item_selected_set(prev, EINA_TRUE);
730    elm_genlist_item_show(prev);
731    return EINA_TRUE;
732 }
733
734 static Eina_Bool
735 _item_single_select_down(Widget_Data *wd)
736 {
737    Elm_Genlist_Item *next;
738    if (!wd->selected)
739      {
740         next = ELM_GENLIST_ITEM_FROM_INLIST(wd->items);
741         while ((next) && (next->delete_me))
742           next = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(next)->next);
743      }
744    else next = elm_genlist_item_next_get(wd->last_selected_item);
745
746    if (!next) return EINA_FALSE;
747
748    _deselect_all_items(wd);
749
750    elm_genlist_item_selected_set(next, EINA_TRUE);
751    elm_genlist_item_show(next);
752    return EINA_TRUE;
753 }
754
755 static void
756 _on_focus_hook(void *data   __UNUSED__,
757                Evas_Object *obj)
758 {
759    Widget_Data *wd = elm_widget_data_get(obj);
760    if (!wd) return;
761    if (elm_widget_focus_get(obj))
762      {
763         edje_object_signal_emit(wd->obj, "elm,action,focus", "elm");
764         evas_object_focus_set(wd->obj, EINA_TRUE);
765         if ((wd->selected) && (!wd->last_selected_item))
766           wd->last_selected_item = eina_list_data_get(wd->selected);
767      }
768    else
769      {
770         edje_object_signal_emit(wd->obj, "elm,action,unfocus", "elm");
771         evas_object_focus_set(wd->obj, EINA_FALSE);
772      }
773 }
774
775 static void
776 _del_hook(Evas_Object *obj)
777 {
778    Widget_Data *wd = elm_widget_data_get(obj);
779    if (!wd) return;
780    _item_cache_zero(wd);
781    if (wd->calc_job) ecore_job_del(wd->calc_job);
782    if (wd->update_job) ecore_job_del(wd->update_job);
783    if (wd->changed_job) ecore_job_del(wd->changed_job);
784    if (wd->must_recalc_idler) ecore_idler_del(wd->must_recalc_idler);
785    if (wd->multi_timer) ecore_timer_del(wd->multi_timer);
786    if (wd->scr_hold_timer) ecore_timer_del(wd->scr_hold_timer);
787    free(wd);
788 }
789
790 static void
791 _del_pre_hook(Evas_Object *obj)
792 {
793    Widget_Data *wd = elm_widget_data_get(obj);
794    if (!wd) return;
795    if (wd->edit_mode) elm_genlist_edit_mode_set(wd->obj, EINA_FALSE);
796    evas_object_del(wd->pan_smart);
797    wd->pan_smart = NULL;
798    elm_genlist_clear(obj);
799 }
800
801 static void
802 _mirrored_set(Evas_Object *obj,
803               Eina_Bool    rtl)
804 {
805    Widget_Data *wd = elm_widget_data_get(obj);
806    if (!wd) return;
807    _item_cache_zero(wd);
808    // TODO: uncomment this after upstream merge
809    //elm_smart_scroller_mirrored_set(wd->scr, rtl);
810 }
811
812 static void
813 _theme_hook(Evas_Object *obj)
814 {
815    Widget_Data *wd = elm_widget_data_get(obj);
816    Item_Block *itb;
817    if (!wd) return;
818    _item_cache_zero(wd);
819    // TODO: uncomment this after upstream merge
820    //_elm_widget_mirrored_reload(obj);
821    //_mirrored_set(obj, elm_widget_mirrored_get(obj));
822    elm_smart_scroller_object_theme_set(obj, wd->scr, "genlist", "base",
823                                        elm_widget_style_get(obj));
824 //   edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
825    wd->item_width = wd->item_height = 0;
826    wd->group_item_width = wd->group_item_height = 0;
827    wd->minw = wd->minh = wd->realminw = 0;
828    EINA_INLIST_FOREACH(wd->blocks, itb)
829      {
830         Eina_List *l;
831         Elm_Genlist_Item *it;
832
833         if (itb->realized) _item_block_unrealize(itb);
834         EINA_LIST_FOREACH(itb->items, l, it)
835           it->mincalcd = EINA_FALSE;
836
837         itb->changed = EINA_TRUE;
838      }
839    if (wd->calc_job) ecore_job_del(wd->calc_job);
840    wd->calc_job = ecore_job_add(_calc_job, wd);
841    _sizing_eval(obj);
842 }
843
844 static void
845 _show_region_hook(void        *data,
846                   Evas_Object *obj)
847 {
848    Widget_Data *wd = elm_widget_data_get(data);
849    Evas_Coord x, y, w, h;
850    if (!wd) return;
851    elm_widget_show_region_get(obj, &x, &y, &w, &h);
852    //x & y are screen coordinates, Add with pan coordinates
853    x += wd->pan_x;
854    y += wd->pan_y;
855    if (y > 0) elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
856 }
857
858 static void
859 _sizing_eval(Evas_Object *obj)
860 {
861    Widget_Data *wd = elm_widget_data_get(obj);
862    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
863    if (!wd) return;
864    evas_object_size_hint_min_get(wd->scr, &minw, &minh);
865    evas_object_size_hint_max_get(wd->scr, &maxw, &maxh);
866    minh = -1;
867    if (wd->height_for_width)
868      {
869         Evas_Coord vw, vh;
870
871         elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
872         if ((vw != 0) && (vw != wd->prev_viewport_w))
873           {
874              Item_Block *itb;
875
876              wd->prev_viewport_w = vw;
877              EINA_INLIST_FOREACH(wd->blocks, itb)
878                {
879                   itb->must_recalc = EINA_TRUE;
880                }
881              if (wd->calc_job) ecore_job_del(wd->calc_job);
882              wd->calc_job = ecore_job_add(_calc_job, wd);
883           }
884      }
885    if (wd->mode == ELM_LIST_LIMIT)
886      {
887         Evas_Coord vmw, vmh, vw, vh;
888
889         minw = wd->realminw;
890         maxw = -1;
891         elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
892         if ((minw > 0) && (vw < minw)) vw = minw;
893         else if ((maxw > 0) && (vw > maxw))
894           vw = maxw;
895         edje_object_size_min_calc
896           (elm_smart_scroller_edje_object_get(wd->scr), &vmw, &vmh);
897         minw = vmw + minw;
898      }
899    else
900      {
901         Evas_Coord vmw, vmh;
902
903         edje_object_size_min_calc
904           (elm_smart_scroller_edje_object_get(wd->scr), &vmw, &vmh);
905         minw = vmw;
906         minh = vmh;
907      }
908    evas_object_size_hint_min_set(obj, minw, minh);
909    evas_object_size_hint_max_set(obj, maxw, maxh);
910 }
911
912 static void
913 _item_highlight(Elm_Genlist_Item *it)
914 {
915    const char *selectraise;
916    if ((it->wd->no_select) || (it->delete_me) || (it->highlighted) || (it->disabled) || (it->display_only)) return;
917    if ((!it->sweeped) && (!it->wd->edit_mode))
918       edje_object_signal_emit(it->base.view, "elm,state,selected", "elm");
919    selectraise = edje_object_data_get(it->base.view, "selectraise");
920    if ((selectraise) && (!strcmp(selectraise, "on")))
921      {
922         if (!it->wd->edit_mode) evas_object_raise(it->base.view);
923         if ((it->group_item) && (it->group_item->realized))
924            evas_object_raise(it->group_item->base.view);
925      }
926    it->highlighted = EINA_TRUE;
927 }
928
929 static void
930 _item_block_del(Elm_Genlist_Item *it)
931 {
932    Eina_Inlist *il;
933    Item_Block *itb = it->block;
934
935    itb->items = eina_list_remove(itb->items, it);
936    itb->count--;
937    itb->changed = EINA_TRUE;
938    if (!it->wd->reorder_deleted)
939      {
940         if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
941         it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
942      }
943    if (itb->count < 1)
944      {
945         il = EINA_INLIST_GET(itb);
946         Item_Block *itbn = (Item_Block *)(il->next);
947         if (it->parent)
948           it->parent->items = eina_list_remove(it->parent->items, it);
949         else
950           it->wd->blocks = eina_inlist_remove(it->wd->blocks, il);
951         free(itb);
952         if (itbn) itbn->changed = EINA_TRUE;
953      }
954    else
955      {
956         if (itb->count < itb->wd->max_items_per_block/2)
957           {
958              il = EINA_INLIST_GET(itb);
959              Item_Block *itbp = (Item_Block *)(il->prev);
960              Item_Block *itbn = (Item_Block *)(il->next);
961              if ((itbp) && ((itbp->count + itb->count) < itb->wd->max_items_per_block + itb->wd->max_items_per_block/2))
962                {
963                   Elm_Genlist_Item *it2;
964
965                   EINA_LIST_FREE(itb->items, it2)
966                     {
967                        it2->block = itbp;
968                        itbp->items = eina_list_append(itbp->items, it2);
969                        itbp->count++;
970                        itbp->changed = EINA_TRUE;
971                     }
972                   it->wd->blocks = eina_inlist_remove(it->wd->blocks,
973                                                       EINA_INLIST_GET(itb));
974                   free(itb);
975                }
976              else if ((itbn) && ((itbn->count + itb->count) < itb->wd->max_items_per_block + itb->wd->max_items_per_block/2))
977                {
978                   while (itb->items)
979                     {
980                        Eina_List *last = eina_list_last(itb->items);
981                        Elm_Genlist_Item *it2 = last->data;
982
983                        it2->block = itbn;
984                        itb->items = eina_list_remove_list(itb->items, last);
985                        itbn->items = eina_list_prepend(itbn->items, it2);
986                        itbn->count++;
987                        itbn->changed = EINA_TRUE;
988                     }
989                   it->wd->blocks =
990                     eina_inlist_remove(it->wd->blocks, EINA_INLIST_GET(itb));
991                   free(itb);
992                }
993           }
994      }
995 }
996
997 static void
998 _item_subitems_clear(Elm_Genlist_Item *it)
999 {
1000    if (!it) return;
1001    Eina_List *tl = NULL, *l;
1002    Elm_Genlist_Item *it2;
1003
1004    EINA_LIST_FOREACH(it->items, l, it2)
1005       tl = eina_list_append(tl, it2);
1006
1007    EINA_LIST_FREE(tl, it2)
1008      elm_genlist_item_del(it2);
1009 }
1010
1011 static void
1012 _item_del(Elm_Genlist_Item *it)
1013 {
1014    elm_widget_item_pre_notify_del(it);
1015    elm_genlist_item_subitems_clear(it);
1016    it->wd->walking -= it->walking;
1017    if (it->wd->show_item == it) it->wd->show_item = NULL;
1018    if (it->selected) it->wd->selected = eina_list_remove(it->wd->selected, it);
1019    if (it->realized) _item_unrealize(it);
1020    if (it->effect_item_realized) _effect_item_unrealize(it);
1021    if (it->block) _item_block_del(it);
1022    if ((!it->delete_me) && (it->itc->func.del))
1023      it->itc->func.del((void *)it->base.data, it->base.widget);
1024    it->delete_me = EINA_TRUE;
1025    if (it->queued)
1026      it->wd->queue = eina_list_remove(it->wd->queue, it);
1027 #ifdef ANCHOR_ITEM
1028    if (it->wd->anchor_item == it)
1029      {
1030         it->wd->anchor_item = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
1031         if (!it->wd->anchor_item)
1032           it->wd->anchor_item = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
1033      }
1034 #endif
1035    it->wd->items = eina_inlist_remove(it->wd->items, EINA_INLIST_GET(it));
1036    if (it->parent)
1037      it->parent->items = eina_list_remove(it->parent->items, it);
1038    if (it->flags & ELM_GENLIST_ITEM_GROUP)
1039      it->wd->group_items = eina_list_remove(it->wd->group_items, it);
1040    if (it->long_timer) ecore_timer_del(it->long_timer);
1041    if (it->swipe_timer) ecore_timer_del(it->swipe_timer);
1042
1043    if (it->tooltip.del_cb)
1044      it->tooltip.del_cb((void *)it->tooltip.data, it->base.widget, it);
1045
1046    elm_widget_item_del(it);
1047    it->wd->total_num--;  // todo : remove
1048 }
1049
1050 static void
1051 _item_select(Elm_Genlist_Item *it)
1052 {
1053    if ((it->wd->no_select) || (it->delete_me)) return;
1054    if (it->selected)
1055      {
1056         if (it->wd->always_select) goto call;
1057         return;
1058      }
1059    it->selected = EINA_TRUE;
1060    it->wd->selected = eina_list_append(it->wd->selected, it);
1061 call:
1062    it->walking++;
1063    it->wd->walking++;
1064    if (it->func.func) it->func.func((void *)it->func.data, it->base.widget, it);
1065    if (!it->delete_me)
1066      evas_object_smart_callback_call(it->base.widget, "selected", it);
1067    it->walking--;
1068    it->wd->walking--;
1069    if ((it->wd->clear_me) && (!it->wd->walking))
1070      {
1071         elm_genlist_clear(it->base.widget);
1072         return;
1073      }
1074    else
1075      {
1076         if ((!it->walking) && (it->delete_me))
1077           {
1078              if (!it->relcount) _item_del(it);
1079           }
1080      }
1081    if (it && it->wd) it->wd->last_selected_item = it;
1082 }
1083
1084 static void
1085 _item_unselect(Elm_Genlist_Item *it)
1086 {
1087    const char *stacking, *selectraise;
1088
1089    if ((it->delete_me) || (!it->highlighted)) return;
1090    if (!it->sweeped)
1091       edje_object_signal_emit(it->base.view, "elm,state,unselected", "elm");
1092    stacking = edje_object_data_get(it->base.view, "stacking");
1093    selectraise = edje_object_data_get(it->base.view, "selectraise");
1094    if ((selectraise) && (!strcmp(selectraise, "on")))
1095      {
1096         if ((stacking) && (!strcmp(stacking, "below")))
1097           evas_object_lower(it->base.view);
1098      }
1099    it->highlighted = EINA_FALSE;
1100    if (it->selected)
1101      {
1102         it->selected = EINA_FALSE;
1103         it->wd->selected = eina_list_remove(it->wd->selected, it);
1104         evas_object_smart_callback_call(it->base.widget, "unselected", it);
1105      }
1106 }
1107
1108 static void
1109 _mouse_move(void        *data,
1110             Evas *evas   __UNUSED__,
1111             Evas_Object *obj,
1112             void        *event_info)
1113 {
1114    Elm_Genlist_Item *it = data;
1115    Evas_Event_Mouse_Move *ev = event_info;
1116    Evas_Coord minw = 0, minh = 0, x, y, dx, dy, adx, ady;
1117
1118    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
1119      {
1120         if (!it->wd->on_hold)
1121           {
1122              it->wd->on_hold = EINA_TRUE;
1123              if (!it->wd->wasselected)
1124                _item_unselect(it);
1125           }
1126      }
1127    if (it->wd->multitouched)
1128      {
1129         it->wd->cur_x = ev->cur.canvas.x;
1130         it->wd->cur_y = ev->cur.canvas.y;
1131         return;
1132      }
1133    if ((it->dragging) && (it->down))
1134      {
1135         if (it->wd->movements == SWIPE_MOVES) it->wd->swipe = EINA_TRUE;
1136         else
1137           {
1138              it->wd->history[it->wd->movements].x = ev->cur.canvas.x;
1139              it->wd->history[it->wd->movements].y = ev->cur.canvas.y;
1140              if (abs((it->wd->history[it->wd->movements].x -
1141                       it->wd->history[0].x)) > 40)
1142                it->wd->swipe = EINA_TRUE;
1143              else
1144                it->wd->movements++;
1145           }
1146         if (it->long_timer)
1147           {
1148              ecore_timer_del(it->long_timer);
1149              it->long_timer = NULL;
1150           }
1151         evas_object_smart_callback_call(it->base.widget, "drag", it);
1152         return;
1153      }
1154    if ((!it->down) /* || (it->wd->on_hold)*/ || (it->wd->longpressed))
1155      {
1156         if (it->long_timer)
1157           {
1158              ecore_timer_del(it->long_timer);
1159              it->long_timer = NULL;
1160           }
1161         if (it->wd->reorder_mode && it->wd->reorder_it)
1162           {
1163              Evas_Coord ox,oy,oh,ow;
1164              evas_object_geometry_get(it->wd->pan_smart, &ox, &oy, &ow, &oh);
1165              int it_y = ev->cur.canvas.y - it->wd->reorder_it->dy;
1166              if (!it->wd->reorder_start_y) it->wd->reorder_start_y = it->block->y + it->y;
1167
1168              evas_object_resize(it->base.view, it->w, it->h);
1169              if (it_y < oy) _effect_item_controls(it, it->scrl_x, oy);
1170              else if (it_y + it->wd->reorder_it->h > oy+oh) _effect_item_controls(it, it->scrl_x, oy + oh - it->wd->reorder_it->h);
1171              else _effect_item_controls(it, it->scrl_x, it_y);
1172
1173              if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
1174              it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
1175           }
1176         return;
1177      }
1178    if (!it->display_only)
1179      elm_coords_finger_size_adjust(1, &minw, 1, &minh);
1180    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
1181    x = ev->cur.canvas.x - x;
1182    y = ev->cur.canvas.y - y;
1183    dx = x - it->dx;
1184    adx = dx;
1185    if (adx < 0) adx = -dx;
1186    dy = y - it->dy;
1187    ady = dy;
1188    if (ady < 0) ady = -dy;
1189    minw /= 2;
1190    minh /= 2;
1191    if ((adx > minw) || (ady > minh))
1192      {
1193         it->dragging = EINA_TRUE;
1194         if (it->long_timer)
1195           {
1196              ecore_timer_del(it->long_timer);
1197              it->long_timer = NULL;
1198           }
1199         if (!it->wd->wasselected)
1200           _item_unselect(it);
1201         if (dy < 0)
1202           {
1203              if (ady > adx)
1204                evas_object_smart_callback_call(it->base.widget,
1205                                                "drag,start,up", it);
1206              else
1207                {
1208                   if (dx < 0)
1209                     {
1210                        evas_object_smart_callback_call(it->base.widget,
1211                                                        "drag,start,left", it);
1212                        _item_slide(it, EINA_FALSE);
1213                     }
1214                   else
1215                     {
1216                        evas_object_smart_callback_call(it->base.widget,
1217                                                        "drag,start,right", it);
1218                        _item_slide(it, EINA_TRUE);
1219                     }
1220                }
1221           }
1222         else
1223           {
1224              if (ady > adx)
1225                evas_object_smart_callback_call(it->base.widget,
1226                                                "drag,start,down", it);
1227              else
1228                {
1229                   if (dx < 0)
1230                     {
1231                        evas_object_smart_callback_call(it->base.widget,
1232                                                        "drag,start,left", it);
1233                        _item_slide(it, EINA_FALSE);
1234                     }
1235                   else
1236                     {
1237                        evas_object_smart_callback_call(it->base.widget,
1238                                                        "drag,start,right", it);
1239                        _item_slide(it, EINA_TRUE);
1240                     }
1241                }
1242           }
1243      }
1244 }
1245
1246 static Eina_Bool
1247 _long_press(void *data)
1248 {
1249    Elm_Genlist_Item *it = data;
1250    Elm_Genlist_Item *it_tmp;
1251    static Eina_Bool done = EINA_FALSE;
1252    //static Eina_Bool contracted = EINA_FALSE;
1253    Eina_List *l;
1254    Item_Block *itb;
1255
1256    it->long_timer = NULL;
1257    if ((it->disabled) || (it->dragging) || (it->display_only) || (it->wd->rename_it))
1258      return ECORE_CALLBACK_CANCEL;
1259    it->wd->longpressed = EINA_TRUE;
1260    evas_object_smart_callback_call(it->base.widget, "longpressed", it);
1261    if ((it->wd->reorder_mode) && (it->flags != ELM_GENLIST_ITEM_GROUP))
1262      {
1263         it->wd->reorder_it = it;
1264         it->wd->reorder_start_y = 0;
1265         evas_object_raise(it->edit_obj);
1266         elm_smart_scroller_hold_set(it->wd->scr, EINA_TRUE);
1267         edje_object_signal_emit(it->edit_obj, "elm,action,item,reorder_start", "elm");
1268
1269         EINA_INLIST_FOREACH(it->wd->blocks, itb)
1270           {
1271              if (itb->realized)
1272                {
1273                   done = 1;
1274                   EINA_LIST_FOREACH(itb->items, l, it_tmp)
1275                     {
1276                        if (it_tmp->flags != ELM_GENLIST_ITEM_GROUP && it_tmp->realized)
1277                          {
1278                             _item_unselect(it_tmp);
1279                          }
1280                     }
1281                }
1282              else
1283                {
1284                   if (done) break;
1285                }
1286           }
1287
1288         if (it->items)
1289           {
1290              EINA_LIST_FOREACH(it->items, l, it_tmp)
1291                {
1292                   if (elm_genlist_item_expanded_get(it_tmp))
1293                     {
1294                        elm_genlist_item_expanded_set(it_tmp, EINA_FALSE);
1295                        return ECORE_CALLBACK_RENEW;
1296                     }
1297                }
1298           }
1299         if (elm_genlist_item_expanded_get(it)) {
1300              elm_genlist_item_expanded_set(it, EINA_FALSE);
1301              return ECORE_CALLBACK_RENEW;
1302         }
1303      }
1304
1305    return ECORE_CALLBACK_CANCEL;
1306 }
1307
1308 static void
1309 _swipe(Elm_Genlist_Item *it)
1310 {
1311    int i, sum = 0;
1312
1313    if (!it) return;
1314    if ((it->display_only) || (it->disabled)) return;
1315    it->wd->swipe = EINA_FALSE;
1316    for (i = 0; i < it->wd->movements; i++)
1317      {
1318         sum += it->wd->history[i].x;
1319         if (abs(it->wd->history[0].y - it->wd->history[i].y) > 10) return;
1320      }
1321
1322    sum /= it->wd->movements;
1323    if (abs(sum - it->wd->history[0].x) <= 10) return;
1324    evas_object_smart_callback_call(it->base.widget, "swipe", it);
1325 }
1326
1327 static Eina_Bool
1328 _swipe_cancel(void *data)
1329 {
1330    Elm_Genlist_Item *it = data;
1331
1332    if (!it) return ECORE_CALLBACK_CANCEL;
1333    it->wd->swipe = EINA_FALSE;
1334    it->wd->movements = 0;
1335    return ECORE_CALLBACK_RENEW;
1336 }
1337
1338 static Eina_Bool
1339 _multi_cancel(void *data)
1340 {
1341    Widget_Data *wd = data;
1342
1343    if (!wd) return ECORE_CALLBACK_CANCEL;
1344    wd->multi_timeout = EINA_TRUE;
1345    return ECORE_CALLBACK_RENEW;
1346 }
1347
1348 static void
1349 _multi_touch_gesture_eval(void *data)
1350 {
1351    Elm_Genlist_Item *it = data;
1352
1353    it->wd->multitouched = EINA_FALSE;
1354    if (it->wd->multi_timer)
1355      {
1356         ecore_timer_del(it->wd->multi_timer);
1357         it->wd->multi_timer = NULL;
1358      }
1359    if (it->wd->multi_timeout)
1360      {
1361         it->wd->multi_timeout = EINA_FALSE;
1362         return;
1363      }
1364
1365    Evas_Coord minw = 0, minh = 0;
1366    Evas_Coord off_x, off_y, off_mx, off_my;
1367
1368    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
1369    off_x = abs(it->wd->cur_x - it->wd->prev_x);
1370    off_y = abs(it->wd->cur_y - it->wd->prev_y);
1371    off_mx = abs(it->wd->cur_mx - it->wd->prev_mx);
1372    off_my = abs(it->wd->cur_my - it->wd->prev_my);
1373
1374    if (((off_x > minw) || (off_y > minh)) && ((off_mx > minw) || (off_my > minh)))
1375      {
1376         if ((off_x + off_mx) > (off_y + off_my))
1377           {
1378              if ((it->wd->cur_x > it->wd->prev_x) && (it->wd->cur_mx > it->wd->prev_mx))
1379                evas_object_smart_callback_call(it->base.widget,
1380                                                "multi,swipe,right", it);
1381              else if ((it->wd->cur_x < it->wd->prev_x) && (it->wd->cur_mx < it->wd->prev_mx))
1382                evas_object_smart_callback_call(it->base.widget,
1383                                                "multi,swipe,left", it);
1384              else if (abs(it->wd->cur_x - it->wd->cur_mx) > abs(it->wd->prev_x - it->wd->prev_mx))
1385                evas_object_smart_callback_call(it->base.widget,
1386                                                "multi,pinch,out", it);
1387              else
1388                evas_object_smart_callback_call(it->base.widget,
1389                                                "multi,pinch,in", it);
1390           }
1391         else
1392           {
1393              if ((it->wd->cur_y > it->wd->prev_y) && (it->wd->cur_my > it->wd->prev_my))
1394                evas_object_smart_callback_call(it->base.widget,
1395                                                "multi,swipe,down", it);
1396              else if ((it->wd->cur_y < it->wd->prev_y) && (it->wd->cur_my < it->wd->prev_my))
1397                evas_object_smart_callback_call(it->base.widget,
1398                                                "multi,swipe,up", it);
1399              else if (abs(it->wd->cur_y - it->wd->cur_my) > abs(it->wd->prev_y - it->wd->prev_my))
1400                evas_object_smart_callback_call(it->base.widget,
1401                                                "multi,pinch,out", it);
1402              else
1403                evas_object_smart_callback_call(it->base.widget,
1404                                                "multi,pinch,in", it);
1405           }
1406      }
1407    it->wd->multi_timeout = EINA_FALSE;
1408 }
1409
1410 static void
1411 _multi_down(void            *data,
1412             Evas *evas       __UNUSED__,
1413             Evas_Object *obj __UNUSED__,
1414             void            *event_info)
1415 {
1416    Elm_Genlist_Item *it = data;
1417    Evas_Event_Multi_Down *ev = event_info;
1418
1419    if ((it->wd->multi_device != 0) || (it->wd->multitouched) || (it->wd->multi_timeout)) return;
1420    it->wd->multi_device = ev->device;
1421    it->wd->multi_down = EINA_TRUE;
1422    it->wd->multitouched = EINA_TRUE;
1423    it->wd->prev_mx = ev->canvas.x;
1424    it->wd->prev_my = ev->canvas.y;
1425    if (!it->wd->wasselected) _item_unselect(it);
1426    it->wd->wasselected = EINA_FALSE;
1427    it->wd->longpressed = EINA_FALSE;
1428    if (it->long_timer)
1429      {
1430         ecore_timer_del(it->long_timer);
1431         it->long_timer = NULL;
1432      }
1433    if (it->dragging)
1434      {
1435         it->dragging = EINA_FALSE;
1436         evas_object_smart_callback_call(it->base.widget, "drag,stop", it);
1437      }
1438    if (it->swipe_timer)
1439      {
1440         ecore_timer_del(it->swipe_timer);
1441         it->swipe_timer = NULL;
1442      }
1443    if (it->wd->on_hold)
1444      {
1445         it->wd->swipe = EINA_FALSE;
1446         it->wd->movements = 0;
1447         it->wd->on_hold = EINA_FALSE;
1448      }
1449 }
1450
1451 static void
1452 _multi_up(void            *data,
1453           Evas *evas       __UNUSED__,
1454           Evas_Object *obj __UNUSED__,
1455           void            *event_info)
1456 {
1457    Elm_Genlist_Item *it = data;
1458    Evas_Event_Multi_Up *ev = event_info;
1459
1460    if (it->wd->multi_device != ev->device) return;
1461    it->wd->multi_device = 0;
1462    it->wd->multi_down = EINA_FALSE;
1463    if (it->wd->mouse_down) return;
1464    _multi_touch_gesture_eval(data);
1465 }
1466
1467 static void
1468 _multi_move(void            *data,
1469             Evas *evas       __UNUSED__,
1470             Evas_Object *obj __UNUSED__,
1471             void            *event_info)
1472 {
1473    Elm_Genlist_Item *it = data;
1474    Evas_Event_Multi_Move *ev = event_info;
1475
1476    if (it->wd->multi_device != ev->device) return;
1477    it->wd->cur_mx = ev->cur.canvas.x;
1478    it->wd->cur_my = ev->cur.canvas.y;
1479 }
1480
1481 static void
1482 _mouse_down(void        *data,
1483             Evas *evas   __UNUSED__,
1484             Evas_Object *obj,
1485             void        *event_info)
1486 {
1487    Elm_Genlist_Item *it = data;
1488    Evas_Event_Mouse_Down *ev = event_info;
1489    Evas_Coord x, y;
1490
1491    if (ev->button != 1) return;
1492    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
1493      {
1494         it->wd->on_hold = EINA_TRUE;
1495      }
1496    it->down = EINA_TRUE;
1497    it->dragging = EINA_FALSE;
1498    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
1499    it->dx = ev->canvas.x - x;
1500    it->dy = ev->canvas.y - y;
1501    it->wd->mouse_down = EINA_TRUE;
1502    if (!it->wd->multitouched)
1503      {
1504         it->wd->prev_x = ev->canvas.x;
1505         it->wd->prev_y = ev->canvas.y;
1506         it->wd->multi_timeout = EINA_FALSE;
1507         if (it->wd->multi_timer) ecore_timer_del(it->wd->multi_timer);
1508         it->wd->multi_timer = ecore_timer_add(1, _multi_cancel, it->wd);
1509      }
1510    it->wd->longpressed = EINA_FALSE;
1511    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) it->wd->on_hold = EINA_TRUE;
1512    else it->wd->on_hold = EINA_FALSE;
1513    if (it->wd->on_hold) return;
1514    it->wd->wasselected = it->selected;
1515    _item_highlight(it);
1516    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
1517      if ((!it->disabled) && (!it->display_only))
1518        evas_object_smart_callback_call(it->base.widget, "clicked", it);
1519    if (it->long_timer) ecore_timer_del(it->long_timer);
1520    if (it->swipe_timer) ecore_timer_del(it->swipe_timer);
1521    it->swipe_timer = ecore_timer_add(0.4, _swipe_cancel, it);
1522    if (it->realized)
1523      it->long_timer = ecore_timer_add(it->wd->longpress_timeout, _long_press,
1524                                       it);
1525    else
1526      it->long_timer = NULL;
1527    it->wd->swipe = EINA_FALSE;
1528    it->wd->movements = 0;
1529 }
1530
1531 static void
1532 _mouse_up(void            *data,
1533           Evas *evas       __UNUSED__,
1534           Evas_Object *obj __UNUSED__,
1535           void            *event_info)
1536 {
1537    Elm_Genlist_Item *it = data;
1538    Evas_Event_Mouse_Up *ev = event_info;
1539    Eina_Bool dragged = EINA_FALSE;
1540
1541    if (ev->button != 1) return;
1542    it->down = EINA_FALSE;
1543    it->wd->mouse_down = EINA_FALSE;
1544    if (it->wd->multitouched)
1545      {
1546         if (it->wd->multi_down) return;
1547         _multi_touch_gesture_eval(data);
1548         return;
1549      }
1550    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) it->wd->on_hold = EINA_TRUE;
1551    else it->wd->on_hold = EINA_FALSE;
1552    if (it->long_timer)
1553      {
1554         ecore_timer_del(it->long_timer);
1555         it->long_timer = NULL;
1556      }
1557    if (it->dragging)
1558      {
1559         it->dragging = EINA_FALSE;
1560         evas_object_smart_callback_call(it->base.widget, "drag,stop", it);
1561         dragged = 1;
1562      }
1563    if (it->swipe_timer)
1564      {
1565         ecore_timer_del(it->swipe_timer);
1566         it->swipe_timer = NULL;
1567      }
1568    if (it->wd->multi_timer)
1569      {
1570         ecore_timer_del(it->wd->multi_timer);
1571         it->wd->multi_timer = NULL;
1572         it->wd->multi_timeout = EINA_FALSE;
1573      }
1574    if (it->wd->on_hold)
1575      {
1576         if (it->wd->swipe) _swipe(data);
1577         it->wd->longpressed = EINA_FALSE;
1578         it->wd->on_hold = EINA_FALSE;
1579         return;
1580      }
1581    if (it->wd->reorder_mode)
1582      {
1583         Evas_Coord rox, roy, row, roh;
1584         Elm_Genlist_Item *reorder_it = it->wd->reorder_it;
1585         if (reorder_it)
1586           {
1587              Evas_Coord ox,oy,oh,ow;
1588              evas_object_geometry_get(it->wd->pan_smart, &ox, &oy, &ow, &oh);
1589              evas_object_geometry_get(it->wd->reorder_it->base.view, &rox, &roy, &row, &roh);
1590              if (it->wd->reorder_rel)
1591                {
1592                   if (it->wd->reorder_it->parent == it->wd->reorder_rel->parent)  // todo : refactoring
1593                     {
1594                        if (roy + oy <= it->wd->reorder_rel->scrl_y)
1595                           _effect_item_move_before(it->wd->reorder_it, it->wd->reorder_rel);
1596                        else
1597                           _effect_item_move_after(it->wd->reorder_it, it->wd->reorder_rel);
1598                     }
1599                }
1600             it->wd->reorder_deleted = EINA_FALSE;
1601             it->wd->reorder_it = it->wd->reorder_rel = NULL;
1602             elm_smart_scroller_hold_set(it->wd->scr, EINA_FALSE);
1603             edje_object_signal_emit(it->edit_obj, "elm,action,item,reorder_end", "elm");
1604          }
1605       }
1606    if (it->wd->longpressed)
1607      {
1608         it->wd->longpressed = EINA_FALSE;
1609         if (!it->wd->wasselected)
1610           _item_unselect(it);
1611         it->wd->wasselected = EINA_FALSE;
1612         return;
1613      }
1614    if (dragged)
1615      {
1616         if (it->want_unrealize)
1617           {
1618              _item_unrealize(it);
1619              if (it->block->want_unrealize)
1620                _item_block_unrealize(it->block);
1621           }
1622      }
1623    if ((it->disabled) || (dragged) || (it->display_only)) return;
1624    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
1625    if (it->wd->multi)
1626      {
1627         if ((!it->selected) && (!it->sweeped))
1628           {
1629              _item_highlight(it);
1630              _item_select(it);
1631           }
1632         else _item_unselect(it);
1633      }
1634    else
1635      {
1636         if (!it->selected)
1637           {
1638              Widget_Data *wd = it->wd;
1639              if (wd)
1640                {
1641                   while (wd->selected) _item_unselect(wd->selected->data);
1642                }
1643           }
1644         else
1645           {
1646              const Eina_List *l, *l_next;
1647              Elm_Genlist_Item *it2;
1648
1649              EINA_LIST_FOREACH_SAFE(it->wd->selected, l, l_next, it2)
1650                if (it2 != it) _item_unselect(it2);
1651              //_item_highlight(it);
1652              //_item_select(it);
1653           }
1654         if (!it->sweeped)
1655           {
1656              _item_highlight(it);
1657              _item_select(it);
1658           }
1659      }
1660 }
1661
1662 static void
1663 _signal_expand_toggle(void                *data,
1664                       Evas_Object *obj     __UNUSED__,
1665                       const char *emission __UNUSED__,
1666                       const char *source   __UNUSED__)
1667 {
1668    Elm_Genlist_Item *it = data;
1669
1670    if (it->expanded)
1671      evas_object_smart_callback_call(it->base.widget, "contract,request", it);
1672    else
1673      evas_object_smart_callback_call(it->base.widget, "expand,request", it);
1674 }
1675
1676 static void
1677 _signal_expand(void                *data,
1678                Evas_Object *obj     __UNUSED__,
1679                const char *emission __UNUSED__,
1680                const char *source   __UNUSED__)
1681 {
1682    Elm_Genlist_Item *it = data;
1683
1684    if (!it->expanded)
1685      evas_object_smart_callback_call(it->base.widget, "expand,request", it);
1686 }
1687
1688 static void
1689 _signal_contract(void                *data,
1690                  Evas_Object *obj     __UNUSED__,
1691                  const char *emission __UNUSED__,
1692                  const char *source   __UNUSED__)
1693 {
1694    Elm_Genlist_Item *it = data;
1695
1696    if (it->expanded)
1697      evas_object_smart_callback_call(it->base.widget, "contract,request", it);
1698 }
1699
1700 static void
1701 _item_cache_clean(Widget_Data *wd)
1702 {
1703    while ((wd->item_cache) && (wd->item_cache_count > wd->item_cache_max))
1704      {
1705         Item_Cache *itc;
1706
1707         itc = EINA_INLIST_CONTAINER_GET(wd->item_cache->last, Item_Cache);
1708         wd->item_cache = eina_inlist_remove(wd->item_cache,
1709                                             wd->item_cache->last);
1710         wd->item_cache_count--;
1711         if (itc->spacer) evas_object_del(itc->spacer);
1712         if (itc->base_view) evas_object_del(itc->base_view);
1713         if (itc->item_style) eina_stringshare_del(itc->item_style);
1714         free(itc);
1715      }
1716 }
1717
1718 static void
1719 _item_cache_zero(Widget_Data *wd)
1720 {
1721    int pmax = wd->item_cache_max;
1722    wd->item_cache_max = 0;
1723    _item_cache_clean(wd);
1724    wd->item_cache_max = pmax;
1725 }
1726
1727 static void
1728 _item_cache_add(Elm_Genlist_Item *it)
1729 {
1730    Item_Cache *itc;
1731
1732    if (it->wd->item_cache_max <= 0)
1733      {
1734         evas_object_del(it->base.view);
1735         it->base.view = NULL;
1736         evas_object_del(it->spacer);
1737         it->spacer = NULL;
1738         return;
1739      }
1740
1741    it->wd->item_cache_count++;
1742    itc = calloc(1, sizeof(Item_Cache));
1743    if (!itc) return;
1744    it->wd->item_cache = eina_inlist_prepend(it->wd->item_cache,
1745                                             EINA_INLIST_GET(itc));
1746    itc->spacer = it->spacer;
1747    it->spacer = NULL;
1748    itc->base_view = it->base.view;
1749    it->base.view = NULL;
1750    evas_object_hide(itc->base_view);
1751    evas_object_move(itc->base_view, -9999, -9999);
1752    itc->item_style = eina_stringshare_add(it->itc->item_style);
1753    if (it->flags & ELM_GENLIST_ITEM_SUBITEMS) itc->tree = 1;
1754    itc->compress = (it->wd->compress);
1755    itc->odd = (it->order_num_in & 0x1);
1756    itc->selected = it->selected;
1757    itc->disabled = it->disabled;
1758    itc->expanded = it->expanded;
1759    if (it->long_timer)
1760      {
1761         ecore_timer_del(it->long_timer);
1762         it->long_timer = NULL;
1763      }
1764    if (it->swipe_timer)
1765      {
1766         ecore_timer_del(it->swipe_timer);
1767         it->swipe_timer = NULL;
1768      }
1769    // FIXME: other callbacks?
1770    edje_object_signal_callback_del_full(itc->base_view,
1771                                         "elm,action,expand,toggle",
1772                                         "elm", _signal_expand_toggle, it);
1773    edje_object_signal_callback_del_full(itc->base_view, "elm,action,expand",
1774                                         "elm",
1775                                         _signal_expand, it);
1776    edje_object_signal_callback_del_full(itc->base_view, "elm,action,contract",
1777                                         "elm", _signal_contract, it);
1778    evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MOUSE_DOWN,
1779                                        _mouse_down, it);
1780    evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MOUSE_UP,
1781                                        _mouse_up, it);
1782    evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MOUSE_MOVE,
1783                                        _mouse_move, it);
1784    evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MULTI_DOWN,
1785                                        _multi_down, it);
1786    evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MULTI_UP,
1787                                        _multi_up, it);
1788    evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MULTI_MOVE,
1789                                        _multi_move, it);
1790    _item_cache_clean(it->wd);
1791 }
1792
1793 static Item_Cache *
1794 _item_cache_find(Elm_Genlist_Item *it)
1795 {
1796    Item_Cache *itc;
1797    Eina_Bool tree = 0, odd;
1798
1799    if (it->flags & ELM_GENLIST_ITEM_SUBITEMS) tree = 1;
1800    odd = (it->order_num_in & 0x1);
1801    EINA_INLIST_FOREACH(it->wd->item_cache, itc)
1802      {
1803         if ((itc->selected) || (itc->disabled) || (itc->expanded))
1804           continue;
1805         if ((itc->tree == tree) &&
1806             (itc->odd == odd) &&
1807             (itc->compress == it->wd->compress) &&
1808             (!strcmp(it->itc->item_style, itc->item_style)))
1809           {
1810              it->wd->item_cache = eina_inlist_remove(it->wd->item_cache,
1811                                                      EINA_INLIST_GET(itc));
1812              it->wd->item_cache_count--;
1813              return itc;
1814           }
1815      }
1816    return NULL;
1817 }
1818
1819 static void
1820 _item_cache_free(Item_Cache *itc)
1821 {
1822    if (itc->spacer) evas_object_del(itc->spacer);
1823    if (itc->base_view) evas_object_del(itc->base_view);
1824    if (itc->item_style) eina_stringshare_del(itc->item_style);
1825    free(itc);
1826 }
1827
1828 static void
1829 _item_realize(Elm_Genlist_Item *it,
1830               int               in,
1831               Eina_Bool         calc)
1832 {
1833    Elm_Genlist_Item *it2;
1834    const char *stacking;
1835    const char *treesize;
1836    char buf[1024];
1837    int depth, tsize = 20;
1838    Item_Cache *itc = NULL;
1839
1840    if ((it->realized) || (it->delete_me)) return;
1841    it->order_num_in = in;
1842    if (it->wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_DELETE) calc = EINA_FALSE;
1843    if (it->nocache && !it->renamed)
1844      it->nocache = EINA_FALSE;
1845    else
1846       itc = _item_cache_find(it);
1847    if ((!it->wd->effect_mode) && (itc))
1848      {
1849         it->base.view = itc->base_view;
1850         itc->base_view = NULL;
1851         it->spacer = itc->spacer;
1852         itc->spacer = NULL;
1853      }
1854    else
1855      {
1856         it->base.view = edje_object_add(evas_object_evas_get(it->base.widget));
1857         edje_object_scale_set(it->base.view,
1858                               elm_widget_scale_get(it->base.widget) *
1859                               _elm_config->scale);
1860         evas_object_smart_member_add(it->base.view, it->wd->pan_smart);
1861         elm_widget_sub_object_add(it->base.widget, it->base.view);
1862
1863         if (it->flags & ELM_GENLIST_ITEM_SUBITEMS)
1864           strncpy(buf, "tree", sizeof(buf));
1865         else strncpy(buf, "item", sizeof(buf));
1866         if (it->wd->compress)
1867           strncat(buf, "_compress", sizeof(buf) - strlen(buf));
1868
1869         if (in & 0x1) strncat(buf, "_odd", sizeof(buf) - strlen(buf));
1870         strncat(buf, "/", sizeof(buf) - strlen(buf));
1871         strncat(buf, it->itc->item_style, sizeof(buf) - strlen(buf));
1872
1873         _elm_theme_object_set(it->base.widget, it->base.view, "genlist", buf,
1874                               elm_widget_style_get(it->base.widget));
1875         // TODO: uncomment this after upstream merge
1876         //edje_object_mirrored_set(it->base.view,
1877         //                         elm_widget_mirrored_get(it->base.widget));
1878         it->spacer =
1879           evas_object_rectangle_add(evas_object_evas_get(it->base.widget));
1880         evas_object_color_set(it->spacer, 0, 0, 0, 0);
1881         elm_widget_sub_object_add(it->base.widget, it->spacer);
1882      }
1883    for (it2 = it, depth = 0; it2->parent; it2 = it2->parent)
1884      {
1885         if (it2->parent->flags != ELM_GENLIST_ITEM_GROUP) depth += 1;
1886      }
1887    it->expanded_depth = depth;
1888    treesize = edje_object_data_get(it->base.view, "treesize");
1889    if (treesize) tsize = atoi(treesize);
1890    evas_object_size_hint_min_set(it->spacer,
1891                                  (depth * tsize) * _elm_config->scale, 1);
1892    edje_object_part_swallow(it->base.view, "elm.swallow.pad", it->spacer);
1893    if (!calc)
1894      {
1895         edje_object_signal_callback_add(it->base.view,
1896                                         "elm,action,expand,toggle",
1897                                         "elm", _signal_expand_toggle, it);
1898         edje_object_signal_callback_add(it->base.view, "elm,action,expand",
1899                                         "elm", _signal_expand, it);
1900         edje_object_signal_callback_add(it->base.view, "elm,action,contract",
1901                                         "elm", _signal_contract, it);
1902         stacking = edje_object_data_get(it->base.view, "stacking");
1903         if (stacking)
1904           {
1905              if (!strcmp(stacking, "below")) evas_object_lower(it->base.view);
1906              else if (!strcmp(stacking, "above"))
1907                evas_object_raise(it->base.view);
1908           }
1909         evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MOUSE_DOWN,
1910                                        _mouse_down, it);
1911         evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MOUSE_UP,
1912                                        _mouse_up, it);
1913         evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MOUSE_MOVE,
1914                                        _mouse_move, it);
1915         evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MULTI_DOWN,
1916                                        _multi_down, it);
1917         evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MULTI_UP,
1918                                        _multi_up, it);
1919         evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MULTI_MOVE,
1920                                        _multi_move, it);
1921         if (itc)
1922           {
1923              if (it->selected != itc->selected)
1924                {
1925                   if ((it->selected) && (!it->sweeped) && (!it->wd->edit_mode))
1926                     edje_object_signal_emit(it->base.view,
1927                                             "elm,state,selected", "elm");
1928                }
1929              if (it->disabled != itc->disabled)
1930                {
1931                   if (it->disabled)
1932                     edje_object_signal_emit(it->base.view,
1933                                             "elm,state,disabled", "elm");
1934                }
1935              if (it->expanded != itc->expanded)
1936                {
1937                   if (it->expanded)
1938                     edje_object_signal_emit(it->base.view,
1939                                             "elm,state,expanded", "elm");
1940                }
1941           }
1942         else
1943           {
1944              if ((it->selected) && (!it->sweeped) && (!it->wd->edit_mode))
1945                 edje_object_signal_emit(it->base.view,
1946                                         "elm,state,selected", "elm");
1947              if (it->disabled)
1948                edje_object_signal_emit(it->base.view,
1949                                        "elm,state,disabled", "elm");
1950              if (it->expanded)
1951                edje_object_signal_emit(it->base.view,
1952                                        "elm,state,expanded", "elm");
1953           }
1954      }
1955
1956    if ((calc) && (it->wd->homogeneous) && ((it->wd->item_width) || ((it->wd->item_width) && (it->wd->group_item_width))))
1957      {
1958         /* homogenous genlist shortcut */
1959         if (!it->mincalcd)
1960           {
1961              if (it->flags & ELM_GENLIST_ITEM_GROUP)
1962                {
1963                   it->w = it->minw = it->wd->group_item_width;
1964                   it->h = it->minh = it->wd->group_item_height;
1965                }
1966              else
1967                {
1968                   it->w = it->minw = it->wd->item_width;
1969                   it->h = it->minh = it->wd->item_height;
1970                }
1971              it->mincalcd = EINA_TRUE;
1972           }
1973      }
1974    else
1975      {
1976         if (it->itc->func.label_get)
1977           {
1978              const Eina_List *l;
1979              const char *key;
1980
1981              it->labels =
1982                elm_widget_stringlist_get(edje_object_data_get(it->base.view,
1983                                                               "labels"));
1984              EINA_LIST_FOREACH(it->labels, l, key)
1985                {
1986                   char *s = it->itc->func.label_get
1987                       ((void *)it->base.data, it->base.widget, l->data);
1988
1989                   if (s)
1990                     {
1991                        edje_object_part_text_set(it->base.view, l->data, s);
1992                        free(s);
1993                     }
1994                   else if (itc)
1995                     edje_object_part_text_set(it->base.view, l->data, "");
1996                }
1997           }
1998         if (it->itc->func.icon_get)
1999           {
2000              const Eina_List *l;
2001              const char *key;
2002
2003              it->icons =
2004                elm_widget_stringlist_get(edje_object_data_get(it->base.view,
2005                                                               "icons"));
2006              EINA_LIST_FOREACH(it->icons, l, key)
2007                {
2008                   Evas_Object *ic = it->itc->func.icon_get
2009                       ((void *)it->base.data, it->base.widget, l->data);
2010
2011                   if (ic)
2012                     {
2013                        it->icon_objs = eina_list_append(it->icon_objs, ic);
2014                        edje_object_part_swallow(it->base.view, key, ic);
2015                        evas_object_show(ic);
2016                        elm_widget_sub_object_add(it->base.widget, ic);
2017                        evas_object_event_callback_add(ic, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, it);
2018                     }
2019                }
2020              if (it->wd->rename_it && it->renamed)
2021                {
2022                   it->icons =
2023                       elm_widget_stringlist_get(edje_object_data_get(it->base.view, "renames"));
2024                   EINA_LIST_FOREACH(it->icons, l, key)
2025                     {
2026                        Evas_Object *ic = it->itc->func.icon_get
2027                        ((void *)it->base.data, it->base.widget, l->data);
2028                        if (ic)
2029                          {
2030                              it->icon_objs = eina_list_append(it->icon_objs, ic);
2031                              edje_object_part_swallow(it->base.view, key, ic);
2032                              evas_object_show(ic);
2033                              elm_widget_sub_object_add(it->base.widget, ic);
2034                          }
2035                     }
2036               }
2037           }
2038         if (it->itc->func.state_get)
2039           {
2040              const Eina_List *l;
2041              const char *key;
2042
2043              it->states =
2044                elm_widget_stringlist_get(edje_object_data_get(it->base.view,
2045                                                               "states"));
2046              EINA_LIST_FOREACH(it->states, l, key)
2047                {
2048                   Eina_Bool on = it->itc->func.state_get
2049                       ((void *)it->base.data, it->base.widget, l->data);
2050
2051                   if (on)
2052                     {
2053                        snprintf(buf, sizeof(buf), "elm,state,%s,active", key);
2054                        edje_object_signal_emit(it->base.view, buf, "elm");
2055                     }
2056                   else if (itc)
2057                     {
2058                        snprintf(buf, sizeof(buf), "elm,state,%s,passive", key);
2059                        edje_object_signal_emit(it->base.view, buf, "elm");
2060                     }
2061                }
2062           }
2063         if (it->sweeped)
2064            _create_sweep_objs(it);
2065         if (!it->mincalcd)
2066           {
2067              Evas_Coord mw = -1, mh = -1;
2068
2069              if (it->wd->height_for_width) mw = it->wd->w;
2070
2071              if (!it->display_only)
2072                elm_coords_finger_size_adjust(1, &mw, 1, &mh);
2073              if (it->wd->height_for_width) mw = it->wd->prev_viewport_w;
2074              edje_object_size_min_restricted_calc(it->base.view, &mw, &mh, mw,
2075                                                   mh);
2076              if (!it->display_only)
2077                elm_coords_finger_size_adjust(1, &mw, 1, &mh);
2078              it->w = it->minw = mw;
2079              it->h = it->minh = mh;
2080              it->mincalcd = EINA_TRUE;
2081
2082              if ((!it->wd->group_item_width) && (it->flags == ELM_GENLIST_ITEM_GROUP))
2083                {
2084                   it->wd->group_item_width = mw;
2085                   it->wd->group_item_height = mh;
2086                }
2087              else if ((!it->wd->item_width) && (it->flags == ELM_GENLIST_ITEM_NONE))
2088                {
2089                   it->wd->item_width = mw;
2090                   it->wd->item_height = mh;
2091                }
2092           }
2093         if (!calc) evas_object_show(it->base.view);
2094      }
2095
2096    if (it->tooltip.content_cb)
2097      {
2098         elm_widget_item_tooltip_content_cb_set(it,
2099                                                it->tooltip.content_cb,
2100                                                it->tooltip.data, NULL);
2101         elm_widget_item_tooltip_style_set(it, it->tooltip.style);
2102      }
2103
2104    if (it->mouse_cursor)
2105      elm_widget_item_cursor_set(it, it->mouse_cursor);
2106
2107    it->realized = EINA_TRUE;
2108    it->want_unrealize = EINA_FALSE;
2109
2110    if (itc) _item_cache_free(itc);
2111    evas_object_smart_callback_call(it->base.widget, "realized", it);
2112    if ((!calc) && (it->wd->edit_mode) && (it->flags != ELM_GENLIST_ITEM_GROUP))
2113      {
2114         if (it->itc->edit_item_style )
2115           {
2116             _effect_item_realize(it, EINA_FALSE);
2117             edje_object_message_signal_process(it->edit_obj);
2118           }
2119      }
2120 }
2121
2122 static void
2123 _item_unrealize(Elm_Genlist_Item *it)
2124 {
2125    Evas_Object *icon;
2126
2127    if (!it->realized) return;
2128    if (it->wd->reorder_it && it->wd->reorder_it == it) return;
2129    evas_object_smart_callback_call(it->base.widget, "unrealized", it);
2130    if (it->long_timer)
2131      {
2132         ecore_timer_del(it->long_timer);
2133         it->long_timer = NULL;
2134      }
2135    if ((it->sweeped) || (it->wassweeped) || (it->nocache))
2136      {
2137         it->sweeped = EINA_FALSE;
2138         it->wassweeped = EINA_FALSE;
2139         it->wd->sweeped_items = eina_list_remove(it->wd->sweeped_items, it);
2140         _delete_sweep_objs(it);
2141         evas_object_del(it->base.view);
2142         it->base.view = NULL;
2143         evas_object_del(it->spacer);
2144         it->spacer = NULL;
2145      }
2146    else
2147      {
2148         // TODO: uncomment this after upstream merge
2149         //edje_object_mirrored_set(it->base.view, elm_widget_mirrored_get(it->base.widget));
2150         _item_cache_add(it);
2151      }
2152    elm_widget_stringlist_free(it->labels);
2153    it->labels = NULL;
2154    elm_widget_stringlist_free(it->icons);
2155    it->icons = NULL;
2156    elm_widget_stringlist_free(it->states);
2157
2158    EINA_LIST_FREE(it->icon_objs, icon)
2159      evas_object_del(icon);
2160
2161    it->states = NULL;
2162    it->realized = EINA_FALSE;
2163    it->want_unrealize = EINA_FALSE;
2164    if (it->wd->edit_mode) _effect_item_unrealize(it);
2165 }
2166
2167 static Eina_Bool
2168 _item_block_recalc(Item_Block *itb,
2169                    int         in,
2170                    int         qadd,
2171                    int         norender)
2172 {
2173    const Eina_List *l;
2174    Elm_Genlist_Item *it;
2175    Evas_Coord minw = 0, minh = 0;
2176    Eina_Bool showme = EINA_FALSE, changed = EINA_FALSE;
2177    Evas_Coord y = 0;
2178
2179    itb->num = in;
2180    EINA_LIST_FOREACH(itb->items, l, it)
2181      {
2182         if (it->delete_me) continue;
2183         showme |= it->showme;
2184         if (!itb->realized)
2185           {
2186              if (qadd)
2187                {
2188                   if (!it->mincalcd) changed = EINA_TRUE;
2189                   if (changed)
2190                     {
2191                        _item_realize(it, in, EINA_TRUE);
2192                        _item_unrealize(it);
2193                     }
2194                }
2195              else
2196                {
2197                   _item_realize(it, in, EINA_TRUE);
2198                   if (!it->wd->contracting) _item_unrealize(it);
2199                }
2200           }
2201         else
2202           _item_realize(it, in, EINA_FALSE);
2203         minh += it->minh;
2204         if (minw < it->minw) minw = it->minw;
2205         in++;
2206         it->x = 0;
2207         it->y = y;
2208         y += it->h;
2209      }
2210    itb->minw = minw;
2211    itb->minh = minh;
2212    itb->changed = EINA_FALSE;
2213    /* force an evas norender to garbage collect deleted objects */
2214    if (norender) evas_norender(evas_object_evas_get(itb->wd->obj));
2215    return showme;
2216 }
2217
2218 static void
2219 _item_block_realize(Item_Block *itb,
2220                     int         in,
2221                     int         full)
2222 {
2223    const Eina_List *l;
2224    Elm_Genlist_Item *it;
2225
2226    if (itb->realized) return;
2227    EINA_LIST_FOREACH(itb->items, l, it)
2228      {
2229         if (it->delete_me) continue;
2230         if (full) _item_realize(it, in, EINA_FALSE);
2231         in++;
2232      }
2233    itb->realized = EINA_TRUE;
2234    itb->want_unrealize = EINA_FALSE;
2235 }
2236
2237 static void
2238 _item_block_unrealize(Item_Block *itb)
2239 {
2240    const Eina_List *l;
2241    Elm_Genlist_Item *it;
2242    Eina_Bool dragging = EINA_FALSE;
2243
2244    if (!itb->realized) return;
2245    EINA_LIST_FOREACH(itb->items, l, it)
2246      {
2247         if (it->flags != ELM_GENLIST_ITEM_GROUP)
2248           {
2249              if (it->dragging)
2250                {
2251                   dragging = EINA_TRUE;
2252                   it->want_unrealize = EINA_TRUE;
2253                }
2254              else
2255                 if (!it->wd->contracting) _item_unrealize(it);
2256           }
2257      }
2258    if (!dragging)
2259      {
2260         itb->realized = EINA_FALSE;
2261         itb->want_unrealize = EINA_TRUE;
2262      }
2263    else
2264      itb->want_unrealize = EINA_FALSE;
2265 }
2266
2267 static int
2268 _get_space_for_reorder_item(Elm_Genlist_Item *it)
2269 {
2270    Evas_Coord rox, roy, row, roh;
2271    Eina_Bool top = EINA_FALSE;
2272    Elm_Genlist_Item *reorder_it = it->wd->reorder_it;
2273    if (!reorder_it) return 0;
2274
2275    Evas_Coord   ox,oy,oh,ow;
2276    evas_object_geometry_get(it->wd->pan_smart, &ox, &oy, &ow, &oh);
2277    evas_object_geometry_get(it->wd->reorder_it->base.view, &rox, &roy, &row, &roh);
2278
2279    if ((it->wd->reorder_start_y < it->block->y) && (roy - oy + roh/2 >= it->block->y -  it->wd->pan_y))
2280      {
2281         it->block->reorder_offset = it->wd->reorder_it->h * -1;
2282         if (it->block->count == 1)
2283            it->wd->reorder_rel = it;
2284      }
2285    else if ((it->wd->reorder_start_y >= it->block->y) && (roy - oy + roh/2  <=  it->block->y -  it->wd->pan_y))
2286      {
2287         it->block->reorder_offset = it->wd->reorder_it->h;
2288      }
2289    else
2290      it->block->reorder_offset = 0;
2291
2292    it->scrl_y += it->block->reorder_offset;
2293
2294    top = (ELM_RECTS_INTERSECT(it->scrl_x, it->scrl_y, it->w, it->h,
2295                                             rox, roy+roh/2, row, 1));
2296    if (top)
2297      {
2298         it->wd->reorder_rel = it;
2299         it->scrl_y+=it->wd->reorder_it->h;
2300         return it->wd->reorder_it->h;
2301      }
2302    else
2303      return 0;
2304 }
2305
2306 static Eina_Bool
2307 _reorder_item_moving_effect_timer_cb(void *data)
2308 {
2309    Elm_Genlist_Item *it = data;
2310           Eina_Bool down = EINA_FALSE;
2311    double time = 0.4, t;
2312    int y, dy = 4;
2313    t = ((0.0 > (t = current_time_get() -  it->wd->start_time)) ? 0.0 : t) / 1000;
2314
2315    if (t <= time)
2316       y = (1 * sin((t / time) * (M_PI / 2)) * dy);
2317    else
2318       y = dy;
2319
2320    if (it->old_scrl_y < it->scrl_y)
2321      {
2322         it->old_scrl_y += y;
2323         down = EINA_TRUE;
2324      }
2325    else if (it->old_scrl_y > it->scrl_y)
2326      {
2327         it->old_scrl_y -= y;
2328         down = EINA_FALSE;
2329      }
2330
2331    _effect_item_controls(it,  it->scrl_x, it->old_scrl_y);
2332
2333    _group_items_recalc(it->wd);
2334    if (!it->wd->reorder_it || it->wd->reorder_pan_move)
2335      {
2336         it->old_scrl_y = it->scrl_y;
2337         it->move_effect_me = EINA_FALSE;
2338         it->wd->item_moving_effect_timer = NULL;
2339         return ECORE_CALLBACK_CANCEL;
2340      }
2341    if ((down && it->old_scrl_y >= it->scrl_y) || (!down && it->old_scrl_y <= it->scrl_y))
2342      {
2343         it->old_scrl_y = it->scrl_y;
2344         it->move_effect_me = EINA_FALSE;
2345         it->wd->item_moving_effect_timer = NULL;
2346         return ECORE_CALLBACK_CANCEL;
2347      }
2348    return ECORE_CALLBACK_RENEW;
2349 }
2350
2351 static void
2352 _item_block_position(Item_Block *itb,
2353                      int         in)
2354 {
2355    const Eina_List *l;
2356    Elm_Genlist_Item *it;
2357    Elm_Genlist_Item *git;
2358    Evas_Coord y = 0, ox, oy, ow, oh, cvx, cvy, cvw, cvh;
2359    int vis = 0;
2360
2361    evas_object_geometry_get(itb->wd->pan_smart, &ox, &oy, &ow, &oh);
2362    evas_output_viewport_get(evas_object_evas_get(itb->wd->obj), &cvx, &cvy,
2363                             &cvw, &cvh);
2364
2365    EINA_LIST_FOREACH(itb->items, l, it)
2366      {
2367         if (it->delete_me) continue;
2368         else if (it->wd->reorder_it && it->wd->reorder_it == it) continue;
2369
2370         it->x = 0;
2371         it->y = y;
2372         it->w = itb->w;
2373         it->scrl_x = itb->x + it->x - it->wd->pan_x + ox;
2374         it->scrl_y = itb->y + it->y - it->wd->pan_y + oy;
2375
2376         vis = (ELM_RECTS_INTERSECT(it->scrl_x, it->scrl_y, it->w, it->h,
2377                                    cvx, cvy, cvw, cvh));
2378         if (it->flags != ELM_GENLIST_ITEM_GROUP || (it->wd->reorder_it ))
2379           {
2380              if ((itb->realized) && (!it->realized))
2381                {
2382                   if (vis)
2383                     {
2384                        _item_realize(it, in, 0);
2385                        if (it->renamed)
2386                          {
2387                             if (it->wd->edit_mode) edje_object_signal_emit(it->edit_obj, "elm,state,rename,enabled", "elm");
2388                             edje_object_signal_emit(it->base.view, "elm,state,rename,enabled", "elm");
2389                          }
2390                     }
2391                }
2392              if (it->realized)
2393                {
2394                   if (vis)
2395                     {
2396                        if(it->wd->reorder_mode)
2397                           y += _get_space_for_reorder_item(it);
2398                        git = it->group_item;
2399                        if (git)
2400                          {
2401                             git->scrl_x = it->scrl_x;
2402                             if (git->scrl_y < oy)
2403                                git->scrl_y = oy;
2404                             if ((git->scrl_y + git->h) > (it->scrl_y + it->h))
2405                               git->scrl_y = (it->scrl_y + it->h) - git->h;
2406                             git->want_realize = EINA_TRUE;
2407                          }
2408                        if (it->wd->reorder_it && !it->wd->reorder_pan_move && it->old_scrl_y && it->old_scrl_y != it->scrl_y)
2409                          {
2410                             if (!it->move_effect_me)
2411                               {
2412                                  it->move_effect_me = EINA_TRUE;
2413                                  it->item_moving_effect_timer = ecore_animator_add(_reorder_item_moving_effect_timer_cb, it);
2414                               }
2415
2416                          }
2417                        if (!it->move_effect_me )
2418                             if (!it->wd->effect_mode || it->wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_NONE || ((it->wd->move_effect_mode != ELM_GENLIST_ITEM_MOVE_EFFECT_DELETE) && it->parent == it->wd->expand_item))
2419                             {
2420                               if (it->wd->edit_mode && it->itc->edit_item_style)
2421                                 {
2422                                   _effect_item_controls(it,  it->scrl_x, it->scrl_y);
2423                                 }
2424                               else
2425                                {
2426                                   evas_object_resize(it->base.view, it->w, it->h);
2427                                   evas_object_move(it->base.view, it->scrl_x, it->scrl_y);
2428                                   if((!it->wd->effect_mode || it->wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_NONE) || ((it->wd->move_effect_mode != ELM_GENLIST_ITEM_MOVE_EFFECT_NONE) && (it->old_scrl_y == it->scrl_y)))
2429                                      evas_object_show(it->base.view);
2430                                   else
2431                                      evas_object_hide(it->base.view);
2432                                }
2433                                it->old_scrl_x = it->scrl_x;
2434                                it->old_scrl_y = it->scrl_y;
2435                             }
2436                     }
2437                   else
2438                     {
2439                        if (!it->dragging) _item_unrealize(it);
2440                     }
2441                }
2442              in++;
2443           }
2444         else
2445           {
2446              if (vis) it->want_realize = EINA_TRUE;
2447           }
2448         y += it->h;
2449      }
2450 }
2451
2452 static void
2453 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
2454 {
2455    Elm_Genlist_Item *it = data;
2456    if (!it) return;
2457    it->mincalcd = EINA_FALSE;
2458    it->block->updateme = EINA_TRUE;
2459    if (it->wd->changed_job) ecore_job_del(it->wd->changed_job);
2460    it->wd->changed_job = ecore_job_add(_changed_job, it->wd);
2461 }
2462
2463 static void
2464 _group_items_recalc(void *data)
2465 {
2466    Widget_Data *wd = data;
2467    Eina_List *l;
2468    Elm_Genlist_Item *git;
2469
2470    EINA_LIST_FOREACH(wd->group_items, l, git)
2471      {
2472         if (git->want_realize)
2473           {
2474              if (!git->realized)
2475                _item_realize(git, 0, EINA_FALSE);
2476              evas_object_resize(git->base.view, wd->minw, git->h);
2477              evas_object_move(git->base.view, git->scrl_x, git->scrl_y);
2478              evas_object_show(git->base.view);
2479              evas_object_raise(git->base.view);
2480           }
2481         else if (!git->want_realize && git->realized)
2482           {
2483              if (!git->dragging)
2484                _item_unrealize(git);
2485           }
2486      }
2487 }
2488
2489 static Eina_Bool
2490 _must_recalc_idler(void *data)
2491 {
2492    Widget_Data *wd = data;
2493    if (wd->calc_job) ecore_job_del(wd->calc_job);
2494    wd->calc_job = ecore_job_add(_calc_job, wd);
2495    wd->must_recalc_idler = NULL;
2496    return ECORE_CALLBACK_CANCEL;
2497 }
2498
2499 static void
2500 _calc_job(void *data)
2501 {
2502    Widget_Data *wd = data;
2503    Item_Block *itb;
2504    Evas_Coord minw = -1, minh = 0, y = 0, ow;
2505    Item_Block *chb = NULL;
2506    int in = 0, minw_change = 0;
2507    Eina_Bool changed = EINA_FALSE;
2508    double t0, t;
2509    Eina_Bool did_must_recalc = EINA_FALSE;
2510    if (!wd) return;
2511
2512    t0 = ecore_time_get();
2513    evas_object_geometry_get(wd->pan_smart, NULL, NULL, &ow, &wd->h);
2514    if (wd->w != ow)
2515      {
2516         wd->w = ow;
2517 //        if (wd->height_for_width) changed = EINA_TRUE;
2518      }
2519
2520    EINA_INLIST_FOREACH(wd->blocks, itb)
2521      {
2522         Eina_Bool showme = EINA_FALSE;
2523
2524       itb->num = in;
2525       showme = itb->showme;
2526       itb->showme = EINA_FALSE;
2527       if (chb)
2528         {
2529            if (itb->realized) _item_block_unrealize(itb);
2530         }
2531       if ((itb->changed) || (changed) ||
2532           ((itb->must_recalc) && (!did_must_recalc)))
2533         {
2534            if ((changed) || (itb->must_recalc))
2535              {
2536                 Eina_List *l;
2537                 Elm_Genlist_Item *it;
2538                 EINA_LIST_FOREACH(itb->items, l, it)
2539                   if (it->mincalcd) it->mincalcd = EINA_FALSE;
2540                 itb->changed = EINA_TRUE;
2541                 if (itb->must_recalc) did_must_recalc = EINA_TRUE;
2542                 itb->must_recalc = EINA_FALSE;
2543              }
2544            if (itb->realized) _item_block_unrealize(itb);
2545            showme = _item_block_recalc(itb, in, 0, 1);
2546            chb = itb;
2547         }
2548       itb->y = y;
2549       itb->x = 0;
2550       minh += itb->minh;
2551       if (minw == -1) minw = itb->minw;
2552       else if ((!itb->must_recalc) && (minw < itb->minw))
2553         {
2554            minw = itb->minw;
2555            minw_change = 1;
2556         }
2557       itb->w = minw;
2558       itb->h = itb->minh;
2559       y += itb->h;
2560       in += itb->count;
2561       if ((showme) && (wd->show_item) && (!wd->show_item->queued))
2562         {
2563            wd->show_item->showme = EINA_FALSE;
2564            if (wd->bring_in)
2565              elm_smart_scroller_region_bring_in(wd->scr,
2566                                                 wd->show_item->x +
2567                                                 wd->show_item->block->x,
2568                                                 wd->show_item->y +
2569                                                 wd->show_item->block->y,
2570                                                 wd->show_item->block->w,
2571                                                 wd->show_item->h);
2572            else
2573              elm_smart_scroller_child_region_show(wd->scr,
2574                                                   wd->show_item->x +
2575                                                   wd->show_item->block->x,
2576                                                   wd->show_item->y +
2577                                                   wd->show_item->block->y,
2578                                                   wd->show_item->block->w,
2579                                                   wd->show_item->h);
2580            wd->show_item = NULL;
2581         }
2582    }
2583    if (minw_change)
2584      {
2585         EINA_INLIST_FOREACH(wd->blocks, itb)
2586           {
2587              itb->minw = minw;
2588              itb->w = itb->minw;
2589           }
2590      }
2591    if ((chb) && (EINA_INLIST_GET(chb)->next))
2592      {
2593         EINA_INLIST_FOREACH(EINA_INLIST_GET(chb)->next, itb)
2594           {
2595              if (itb->realized) _item_block_unrealize(itb);
2596           }
2597      }
2598    wd->realminw = minw;
2599    if (minw < wd->w) minw = wd->w;
2600    if ((minw != wd->minw) || (minh != wd->minh))
2601      {
2602         wd->minw = minw;
2603         wd->minh = minh;
2604         if (wd->move_effect_mode != ELM_GENLIST_ITEM_MOVE_EFFECT_DELETE)
2605            evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
2606         _sizing_eval(wd->obj);
2607 #ifdef ANCHOR_ITEM
2608         if ((wd->anchor_item) && (wd->anchor_item->block) && (!wd->auto_scrolled))
2609           {
2610              Elm_Genlist_Item *it;
2611              Evas_Coord it_y;
2612
2613              it = wd->anchor_item;
2614              it_y = wd->anchor_y;
2615              elm_smart_scroller_child_pos_set(wd->scr, wd->pan_x,
2616                                               it->block->y + it->y + it_y);
2617              wd->anchor_item = it;
2618              wd->anchor_y = it_y;
2619           }
2620 #endif
2621      }
2622    t = ecore_time_get();
2623    if (did_must_recalc)
2624      {
2625         if (!wd->must_recalc_idler)
2626           wd->must_recalc_idler = ecore_idler_add(_must_recalc_idler, wd);
2627      }
2628    wd->calc_job = NULL;
2629    evas_object_smart_changed(wd->pan_smart);
2630 }
2631
2632 static void
2633 _update_job(void *data)
2634 {
2635    Widget_Data *wd = data;
2636    Eina_List *l2;
2637    Item_Block *itb;
2638    int num, num0, position = 0, recalc = 0;
2639    if (!wd) return;
2640    wd->update_job = NULL;
2641    num = 0;
2642    EINA_INLIST_FOREACH(wd->blocks, itb)
2643    {
2644       Evas_Coord itminw, itminh;
2645       Elm_Genlist_Item *it;
2646
2647       if (!itb->updateme)
2648         {
2649            num += itb->count;
2650            if (position)
2651              _item_block_position(itb, num);
2652            continue;
2653         }
2654       num0 = num;
2655       recalc = 0;
2656       EINA_LIST_FOREACH(itb->items, l2, it)
2657         {
2658            if (it->updateme)
2659              {
2660                 itminw = it->minw;
2661                 itminh = it->minh;
2662
2663                 it->updateme = EINA_FALSE;
2664                 if (it->realized)
2665                   {
2666                      _item_unrealize(it);
2667                      _item_realize(it, num, 0);
2668                      position = 1;
2669                   }
2670                 else
2671                   {
2672                      _item_realize(it, num, 1);
2673                      _item_unrealize(it);
2674                   }
2675                 if ((it->minw != itminw) || (it->minh != itminh))
2676                   recalc = 1;
2677              }
2678            num++;
2679         }
2680       itb->updateme = EINA_FALSE;
2681       if (recalc)
2682         {
2683            position = 1;
2684            itb->changed = EINA_TRUE;
2685            _item_block_recalc(itb, num0, 0, 1);
2686            _item_block_position(itb, num0);
2687         }
2688    }
2689    if (position)
2690      {
2691         if (wd->calc_job) ecore_job_del(wd->calc_job);
2692         wd->calc_job = ecore_job_add(_calc_job, wd);
2693      }
2694 }
2695
2696 static void
2697 _changed_job(void *data)
2698 {
2699    Widget_Data *wd = data; Eina_List *l2;
2700    Item_Block *itb;
2701    int num, num0, position = 0, recalc = 0;
2702    if (!wd) return;
2703    wd->changed_job = NULL;
2704    num = 0;
2705    EINA_INLIST_FOREACH(wd->blocks, itb)
2706    {
2707       Evas_Coord itminw, itminh;
2708       Elm_Genlist_Item *it;
2709
2710       if (!itb->updateme)
2711         {
2712            num += itb->count;
2713            if (position)
2714              _item_block_position(itb, num);
2715            continue;
2716         }
2717       num0 = num;
2718       recalc = 0;
2719       EINA_LIST_FOREACH(itb->items, l2, it)
2720       {
2721          if (!it->mincalcd)
2722            {
2723               Evas_Coord mw = -1, mh = -1;
2724               itminw = it->w;
2725               itminh = it->h;
2726
2727               if (it->wd->height_for_width) mw = it->wd->w;
2728               if (!it->display_only)
2729                 elm_coords_finger_size_adjust(1, &mw, 1, &mh);
2730               if (it->wd->height_for_width) mw = it->wd->prev_viewport_w;
2731               edje_object_size_min_restricted_calc(it->base.view, &mw, &mh, mw, mh);
2732               if (!it->display_only)
2733                 elm_coords_finger_size_adjust(1, &mw, 1, &mh);
2734               it->w = it->minw = mw;
2735               it->h = it->minh = mh;
2736               it->mincalcd = EINA_TRUE;
2737
2738               //if ((it->minw != itminw) || (it->minh != itminh))
2739               if ((it->minh != itminh))
2740                 recalc = 1;
2741            }
2742          num++;
2743       }
2744       itb->updateme = EINA_FALSE;
2745       if (recalc)
2746         {
2747            position = 1;
2748            itb->changed = EINA_TRUE;
2749            _item_block_recalc(itb, num0, 0, 1);
2750            _item_block_position(itb, num0);
2751         }
2752    }
2753    if (position)
2754      {
2755         if (wd->calc_job) ecore_job_del(wd->calc_job);
2756         wd->calc_job = ecore_job_add(_calc_job, wd);
2757      }
2758 }
2759
2760 static void
2761 _pan_set(Evas_Object *obj,
2762          Evas_Coord   x,
2763          Evas_Coord   y)
2764 {
2765    Pan *sd = evas_object_smart_data_get(obj);
2766    //Item_Block *itb;
2767
2768 //   Evas_Coord ow, oh;
2769 //   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
2770 //   ow = sd->wd->minw - ow;
2771 //   if (ow < 0) ow = 0;
2772 //   oh = sd->wd->minh - oh;
2773 //   if (oh < 0) oh = 0;
2774 //   if (x < 0) x = 0;
2775 //   if (y < 0) y = 0;
2776 //   if (x > ow) x = ow;
2777 //   if (y > oh) y = oh;
2778    if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return;
2779    sd->wd->pan_x = x;
2780    sd->wd->pan_y = y;
2781
2782 #ifdef ANCHOR_ITEM
2783    EINA_INLIST_FOREACH(sd->wd->blocks, itb)
2784    {
2785       if ((itb->y + itb->h) > y)
2786         {
2787            Elm_Genlist_Item *it;
2788            Eina_List *l2;
2789
2790            EINA_LIST_FOREACH(itb->items, l2, it)
2791              {
2792                 if ((itb->y + it->y) >= y)
2793                   {
2794                      sd->wd->anchor_item = it;
2795                      sd->wd->anchor_y = -(itb->y + it->y - y);
2796                      goto done;
2797                   }
2798              }
2799         }
2800    }
2801 done:
2802 #endif
2803    if(!sd->wd->item_moving_effect_timer) evas_object_smart_changed(obj);
2804 }
2805
2806 static void
2807 _pan_get(Evas_Object *obj,
2808          Evas_Coord  *x,
2809          Evas_Coord  *y)
2810 {
2811    Pan *sd = evas_object_smart_data_get(obj);
2812
2813    if (x) *x = sd->wd->pan_x;
2814    if (y) *y = sd->wd->pan_y;
2815 }
2816
2817 static void
2818 _pan_max_get(Evas_Object *obj,
2819              Evas_Coord  *x,
2820              Evas_Coord  *y)
2821 {
2822    Pan *sd = evas_object_smart_data_get(obj);
2823    Evas_Coord ow, oh;
2824
2825    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
2826    ow = sd->wd->minw - ow;
2827    if (ow < 0) ow = 0;
2828    oh = sd->wd->minh - oh;
2829    if (oh < 0) oh = 0;
2830    if (x) *x = ow;
2831    if (y) *y = oh;
2832 }
2833
2834 static void
2835 _pan_min_get(Evas_Object *obj __UNUSED__,
2836              Evas_Coord      *x,
2837              Evas_Coord      *y)
2838 {
2839    if (x) *x = 0;
2840    if (y) *y = 0;
2841 }
2842
2843 static void
2844 _pan_child_size_get(Evas_Object *obj,
2845                     Evas_Coord  *w,
2846                     Evas_Coord  *h)
2847 {
2848    Pan *sd = evas_object_smart_data_get(obj);
2849
2850    if (w) *w = sd->wd->minw;
2851    if (h) *h = sd->wd->minh;
2852 }
2853
2854 static void
2855 _pan_add(Evas_Object *obj)
2856 {
2857    Pan *sd;
2858    Evas_Object_Smart_Clipped_Data *cd;
2859
2860    _pan_sc.add(obj);
2861    cd = evas_object_smart_data_get(obj);
2862    sd = ELM_NEW(Pan);
2863    if (!sd) return;
2864    sd->__clipped_data = *cd;
2865    free(cd);
2866    evas_object_smart_data_set(obj, sd);
2867 }
2868
2869 static void
2870 _pan_del(Evas_Object *obj)
2871 {
2872    Pan *sd = evas_object_smart_data_get(obj);
2873
2874    if (!sd) return;
2875    if (sd->resize_job)
2876      {
2877         ecore_job_del(sd->resize_job);
2878         sd->resize_job = NULL;
2879      }
2880    _pan_sc.del(obj);
2881 }
2882
2883 static void
2884 _pan_resize_job(void *data)
2885 {
2886    Pan *sd = data;
2887    _sizing_eval(sd->wd->obj);
2888    sd->resize_job = NULL;
2889 }
2890
2891 static void
2892 _pan_resize(Evas_Object *obj,
2893             Evas_Coord   w,
2894             Evas_Coord   h)
2895 {
2896    Pan *sd = evas_object_smart_data_get(obj);
2897    Evas_Coord ow, oh;
2898
2899    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
2900    if ((ow == w) && (oh == h)) return;
2901    if ((sd->wd->height_for_width) && (ow != w))
2902      {
2903         if (sd->resize_job) ecore_job_del(sd->resize_job);
2904         sd->resize_job = ecore_job_add(_pan_resize_job, sd);
2905      }
2906    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
2907    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
2908 }
2909
2910 static void
2911 _pan_calculate(Evas_Object *obj)
2912 {
2913    Pan *sd = evas_object_smart_data_get(obj);
2914    Item_Block *itb;
2915    Evas_Coord ox, oy, ow, oh, cvx, cvy, cvw, cvh;
2916    static Evas_Coord old_pan_y = 0;
2917    int in = 0;
2918    Elm_Genlist_Item *git;
2919    Eina_List *l;
2920
2921    evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
2922    evas_output_viewport_get(evas_object_evas_get(obj), &cvx, &cvy, &cvw, &cvh);
2923    EINA_LIST_FOREACH(sd->wd->group_items, l, git)
2924      {
2925         git->want_realize = EINA_FALSE;
2926      }
2927    EINA_INLIST_FOREACH(sd->wd->blocks, itb)
2928    {
2929       itb->w = sd->wd->minw;
2930       if (ELM_RECTS_INTERSECT(itb->x - sd->wd->pan_x + ox,
2931                               itb->y - sd->wd->pan_y + oy,
2932                               itb->w, itb->h,
2933                               cvx, cvy, cvw, cvh))
2934         {
2935            if ((!itb->realized) || (itb->changed))
2936              _item_block_realize(itb, in, 0);
2937            _item_block_position(itb, in);
2938         }
2939       else
2940         {
2941            if (itb->realized) _item_block_unrealize(itb);
2942         }
2943       in += itb->count;
2944    }
2945    if (!sd->wd->reorder_it || sd->wd->reorder_pan_move)
2946       _group_items_recalc(sd->wd);
2947
2948    if (sd->wd->reorder_mode && sd->wd->reorder_it)
2949      {
2950         if (sd->wd->pan_y != old_pan_y) sd->wd->reorder_pan_move = EINA_TRUE;
2951         else sd->wd->reorder_pan_move = EINA_FALSE;
2952         evas_object_raise(sd->wd->reorder_it->edit_obj);
2953         old_pan_y = sd->wd->pan_y;
2954      }
2955
2956       if (sd->wd->effect_mode &&
2957           ((sd->wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_EXPAND) ||
2958            (sd->wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_CONTRACT) ||
2959            (sd->wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_DELETE)))
2960         {
2961            if (!sd->wd->item_moving_effect_timer)
2962              {
2963                 if (sd->wd->move_effect_mode != ELM_GENLIST_ITEM_MOVE_EFFECT_DELETE)
2964                    _item_flip_effect_show(sd->wd->expand_item);
2965
2966                 evas_object_raise(sd->wd->alpha_bg);
2967                 evas_object_show(sd->wd->alpha_bg);
2968                 elm_smart_scroller_bounce_animator_disabled_set(sd->wd->scr, EINA_TRUE);
2969                 sd->wd->start_time = current_time_get();
2970                 sd->wd->item_moving_effect_timer = ecore_animator_add(_item_moving_effect_timer_cb, sd->wd);
2971              }
2972         }
2973       else _item_auto_scroll(sd->wd);
2974    sd->wd->contracting = EINA_FALSE;
2975  }
2976
2977 static void
2978 _pan_move(Evas_Object *obj,
2979           Evas_Coord x __UNUSED__,
2980           Evas_Coord y __UNUSED__)
2981 {
2982    Pan *sd = evas_object_smart_data_get(obj);
2983
2984    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
2985    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
2986 }
2987
2988 static void
2989 _hold_on(void *data       __UNUSED__,
2990          Evas_Object     *obj,
2991          void *event_info __UNUSED__)
2992 {
2993    Widget_Data *wd = elm_widget_data_get(obj);
2994    if (!wd) return;
2995    elm_smart_scroller_hold_set(wd->scr, 1);
2996 }
2997
2998 static void
2999 _hold_off(void *data       __UNUSED__,
3000           Evas_Object     *obj,
3001           void *event_info __UNUSED__)
3002 {
3003    Widget_Data *wd = elm_widget_data_get(obj);
3004    if (!wd) return;
3005    elm_smart_scroller_hold_set(wd->scr, 0);
3006 }
3007
3008 static void
3009 _freeze_on(void *data       __UNUSED__,
3010            Evas_Object     *obj,
3011            void *event_info __UNUSED__)
3012 {
3013    Widget_Data *wd = elm_widget_data_get(obj);
3014    if (!wd) return;
3015    elm_smart_scroller_freeze_set(wd->scr, 1);
3016 }
3017
3018 static void
3019 _freeze_off(void *data       __UNUSED__,
3020             Evas_Object     *obj,
3021             void *event_info __UNUSED__)
3022 {
3023    Widget_Data *wd = elm_widget_data_get(obj);
3024    if (!wd) return;
3025    elm_smart_scroller_freeze_set(wd->scr, 0);
3026 }
3027
3028 static void
3029 _scroll_edge_left(void            *data,
3030                   Evas_Object *scr __UNUSED__,
3031                   void *event_info __UNUSED__)
3032 {
3033    Evas_Object *obj = data;
3034    evas_object_smart_callback_call(obj, "scroll,edge,left", NULL);
3035 }
3036
3037 static void
3038 _scroll_edge_right(void            *data,
3039                    Evas_Object *scr __UNUSED__,
3040                    void *event_info __UNUSED__)
3041 {
3042    Evas_Object *obj = data;
3043    evas_object_smart_callback_call(obj, "scroll,edge,right", NULL);
3044 }
3045
3046 static void
3047 _scroll_edge_top(void            *data,
3048                  Evas_Object *scr __UNUSED__,
3049                  void *event_info __UNUSED__)
3050 {
3051    Evas_Object *obj = data;
3052    evas_object_smart_callback_call(obj, "scroll,edge,top", NULL);
3053 }
3054
3055 static void
3056 _scroll_edge_bottom(void            *data,
3057                     Evas_Object *scr __UNUSED__,
3058                     void *event_info __UNUSED__)
3059 {
3060    Evas_Object *obj = data;
3061    evas_object_smart_callback_call(obj, "scroll,edge,bottom", NULL);
3062 }
3063
3064 /**
3065  * Add a new Genlist object
3066  *
3067  * @param parent The parent object
3068  * @return The new object or NULL if it cannot be created
3069  *
3070  * @ingroup Genlist
3071  */
3072 EAPI Evas_Object *
3073 elm_genlist_add(Evas_Object *parent)
3074 {
3075    Evas_Object *obj;
3076    Evas *e;
3077    Widget_Data *wd;
3078    Evas_Coord minw, minh;
3079    static Evas_Smart *smart = NULL;
3080
3081    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3082
3083    if (!smart)
3084      {
3085         static Evas_Smart_Class sc;
3086
3087         evas_object_smart_clipped_smart_set(&_pan_sc);
3088         sc = _pan_sc;
3089         sc.name = "elm_genlist_pan";
3090         sc.version = EVAS_SMART_CLASS_VERSION;
3091         sc.add = _pan_add;
3092         sc.del = _pan_del;
3093         sc.resize = _pan_resize;
3094         sc.move = _pan_move;
3095         sc.calculate = _pan_calculate;
3096         if (!(smart = evas_smart_class_new(&sc))) return NULL;
3097      }
3098    wd = ELM_NEW(Widget_Data);
3099    e = evas_object_evas_get(parent);
3100    if (!e) return NULL;
3101    obj = elm_widget_add(e);
3102    ELM_SET_WIDTYPE(widtype, "genlist");
3103    elm_widget_type_set(obj, "genlist");
3104    elm_widget_sub_object_add(parent, obj);
3105    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
3106    elm_widget_data_set(obj, wd);
3107    elm_widget_del_hook_set(obj, _del_hook);
3108    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
3109    elm_widget_theme_hook_set(obj, _theme_hook);
3110    elm_widget_can_focus_set(obj, EINA_TRUE);
3111    elm_widget_event_hook_set(obj, _event_hook);
3112    elm_widget_on_show_region_hook_set(obj, _show_region_hook, obj);
3113
3114    wd->scr = elm_smart_scroller_add(e);
3115    elm_smart_scroller_widget_set(wd->scr, obj);
3116    elm_smart_scroller_object_theme_set(obj, wd->scr, "genlist", "base",
3117                                        elm_widget_style_get(obj));
3118    elm_smart_scroller_bounce_allow_set(wd->scr, EINA_FALSE,
3119                                        _elm_config->thumbscroll_bounce_enable);
3120    elm_widget_resize_object_set(obj, wd->scr);
3121
3122    evas_object_smart_callback_add(wd->scr, "edge,left", _scroll_edge_left, obj);
3123    evas_object_smart_callback_add(wd->scr, "edge,right", _scroll_edge_right,
3124                                   obj);
3125    evas_object_smart_callback_add(wd->scr, "edge,top", _scroll_edge_top, obj);
3126    evas_object_smart_callback_add(wd->scr, "edge,bottom", _scroll_edge_bottom,
3127                                   obj);
3128
3129    wd->obj = obj;
3130    wd->mode = ELM_LIST_SCROLL;
3131    wd->max_items_per_block = MAX_ITEMS_PER_BLOCK;
3132    wd->item_cache_max = wd->max_items_per_block * 2;
3133    wd->longpress_timeout = _elm_config->longpress_timeout;
3134    //wd->effect_mode = _elm_config->effect_enable;
3135 //   wd->effect_mode = EINA_TRUE;
3136
3137    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
3138    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
3139    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
3140    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
3141
3142    wd->pan_smart = evas_object_smart_add(e, smart);
3143    wd->pan = evas_object_smart_data_get(wd->pan_smart);
3144    wd->pan->wd = wd;
3145
3146    elm_smart_scroller_extern_pan_set(wd->scr, wd->pan_smart,
3147                                      _pan_set, _pan_get, _pan_max_get,
3148                                      _pan_min_get, _pan_child_size_get);
3149
3150    edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr),
3151                              &minw, &minh);
3152    evas_object_size_hint_min_set(obj, minw, minh);
3153
3154    // TODO: uncomment this after upstream merge
3155    //_mirrored_set(obj, elm_widget_mirrored_get(obj));
3156    _sizing_eval(obj);
3157    return obj;
3158 }
3159
3160 static Elm_Genlist_Item *
3161 _item_new(Widget_Data                  *wd,
3162           const Elm_Genlist_Item_Class *itc,
3163           const void                   *data,
3164           Elm_Genlist_Item             *parent,
3165           Elm_Genlist_Item_Flags        flags,
3166           Evas_Smart_Cb                 func,
3167           const void                   *func_data)
3168 {
3169    Elm_Genlist_Item *it;
3170
3171    it = elm_widget_item_new(wd->obj, Elm_Genlist_Item);
3172    if (!it) return NULL;
3173    it->wd = wd;
3174    it->itc = itc;
3175    it->base.data = data;
3176    it->parent = parent;
3177    it->flags = flags;
3178    it->func.func = func;
3179    it->func.data = func_data;
3180    it->mouse_cursor = NULL;
3181    it->expanded_depth = 0;
3182    it->num = ++wd->total_num;   // todo : remov
3183    return it;
3184 }
3185
3186 static void
3187 _item_block_add(Widget_Data      *wd,
3188                 Elm_Genlist_Item *it)
3189 {
3190    Item_Block *itb = NULL;
3191
3192    if (!it->rel)
3193      {
3194 newblock:
3195         if (it->rel)
3196           {
3197              itb = calloc(1, sizeof(Item_Block));
3198              if (!itb) return;
3199              itb->wd = wd;
3200              if (!it->rel->block)
3201                {
3202                   wd->blocks =
3203                     eina_inlist_append(wd->blocks, EINA_INLIST_GET(itb));
3204                   itb->items = eina_list_append(itb->items, it);
3205                }
3206              else
3207                {
3208                   if (it->before)
3209                     {
3210                        wd->blocks = eina_inlist_prepend_relative
3211                            (wd->blocks, EINA_INLIST_GET(itb),
3212                            EINA_INLIST_GET(it->rel->block));
3213                        itb->items =
3214                          eina_list_prepend_relative(itb->items, it, it->rel);
3215                     }
3216                   else
3217                     {
3218                        wd->blocks = eina_inlist_append_relative
3219                            (wd->blocks, EINA_INLIST_GET(itb),
3220                            EINA_INLIST_GET(it->rel->block));
3221                        itb->items =
3222                          eina_list_append_relative(itb->items, it, it->rel);
3223                     }
3224                }
3225           }
3226         else
3227           {
3228              if (it->before)
3229                {
3230                   if (wd->blocks)
3231                     {
3232                        itb = (Item_Block *)(wd->blocks);
3233                        if (itb->count >= wd->max_items_per_block)
3234                          {
3235                             itb = calloc(1, sizeof(Item_Block));
3236                             if (!itb) return;
3237                             itb->wd = wd;
3238                             wd->blocks =
3239                               eina_inlist_prepend(wd->blocks,
3240                                                   EINA_INLIST_GET(itb));
3241                          }
3242                     }
3243                   else
3244                     {
3245                        itb = calloc(1, sizeof(Item_Block));
3246                        if (!itb) return;
3247                        itb->wd = wd;
3248                        wd->blocks =
3249                          eina_inlist_prepend(wd->blocks, EINA_INLIST_GET(itb));
3250                     }
3251                   itb->items = eina_list_prepend(itb->items, it);
3252                }
3253              else
3254                {
3255                   if (wd->blocks)
3256                     {
3257                        itb = (Item_Block *)(wd->blocks->last);
3258                        if (itb->count >= wd->max_items_per_block)
3259                          {
3260                             itb = calloc(1, sizeof(Item_Block));
3261                             if (!itb) return;
3262                             itb->wd = wd;
3263                             wd->blocks =
3264                               eina_inlist_append(wd->blocks,
3265                                                  EINA_INLIST_GET(itb));
3266                          }
3267                     }
3268                   else
3269                     {
3270                        itb = calloc(1, sizeof(Item_Block));
3271                        if (!itb) return;
3272                        itb->wd = wd;
3273                        wd->blocks =
3274                          eina_inlist_append(wd->blocks, EINA_INLIST_GET(itb));
3275                     }
3276                   itb->items = eina_list_append(itb->items, it);
3277                }
3278           }
3279      }
3280    else
3281      {
3282         itb = it->rel->block;
3283         if (!itb) goto newblock;
3284         if (it->before)
3285           itb->items = eina_list_prepend_relative(itb->items, it, it->rel);
3286         else
3287           itb->items = eina_list_append_relative(itb->items, it, it->rel);
3288      }
3289    itb->count++;
3290    itb->changed = EINA_TRUE;
3291    it->block = itb;
3292    if (itb->wd->calc_job) ecore_job_del(itb->wd->calc_job);
3293    itb->wd->calc_job = ecore_job_add(_calc_job, itb->wd);
3294    if (it->rel)
3295      {
3296         it->rel->relcount--;
3297         if ((it->rel->delete_me) && (!it->rel->relcount))
3298           _item_del(it->rel);
3299         it->rel = NULL;
3300      }
3301    if (itb->count > itb->wd->max_items_per_block)
3302      {
3303         int newc;
3304         Item_Block *itb2;
3305         Elm_Genlist_Item *it2;
3306
3307         newc = itb->count / 2;
3308         itb2 = calloc(1, sizeof(Item_Block));
3309         if (!itb2) return;
3310         itb2->wd = wd;
3311         wd->blocks =
3312           eina_inlist_append_relative(wd->blocks, EINA_INLIST_GET(itb2),
3313                                       EINA_INLIST_GET(itb));
3314         itb2->changed = EINA_TRUE;
3315         while ((itb->count > newc) && (itb->items))
3316           {
3317              Eina_List *l;
3318
3319              l = eina_list_last(itb->items);
3320              it2 = l->data;
3321              itb->items = eina_list_remove_list(itb->items, l);
3322              itb->count--;
3323
3324              itb2->items = eina_list_prepend(itb2->items, it2);
3325              it2->block = itb2;
3326              itb2->count++;
3327           }
3328      }
3329 }
3330
3331 static int
3332 _queue_process(Widget_Data *wd,
3333                int          norender)
3334 {
3335    int n;
3336    Eina_Bool showme = EINA_FALSE;
3337    double t0, t;
3338
3339    t0 = ecore_time_get();
3340    for (n = 0; (wd->queue) && (n < 128); n++)
3341      {
3342         Elm_Genlist_Item *it;
3343
3344         it = wd->queue->data;
3345         wd->queue = eina_list_remove_list(wd->queue, wd->queue);
3346         it->queued = EINA_FALSE;
3347         _item_block_add(wd, it);
3348         t = ecore_time_get();
3349         if (it->block->changed)
3350           {
3351              showme = _item_block_recalc(it->block, it->block->num, 1,
3352                                          norender);
3353              it->block->changed = 0;
3354           }
3355         if (showme) it->block->showme = EINA_TRUE;
3356         if (eina_inlist_count(wd->blocks) > 1)
3357           {
3358              if ((t - t0) > (ecore_animator_frametime_get())) break;
3359           }
3360      }
3361    return n;
3362 }
3363
3364 static Eina_Bool
3365 _item_idler(void *data)
3366 {
3367    Widget_Data *wd = data;
3368
3369    //xxx
3370    //static double q_start = 0.0;
3371    //if (q_start == 0.0) q_start = ecore_time_get();
3372    //xxx
3373
3374    if (_queue_process(wd, 1) > 0)
3375      {
3376         if (wd->calc_job) ecore_job_del(wd->calc_job);
3377         wd->calc_job = ecore_job_add(_calc_job, wd);
3378      }
3379    if (!wd->queue)
3380      {
3381         //xxx
3382         //printf("PROCESS TIME: %3.3f\n", ecore_time_get() - q_start);
3383         //xxx
3384         wd->queue_idler = NULL;
3385         return ECORE_CALLBACK_CANCEL;
3386      }
3387    return ECORE_CALLBACK_RENEW;
3388 }
3389
3390 static void
3391 _item_queue(Widget_Data      *wd,
3392             Elm_Genlist_Item *it)
3393 {
3394    if (it->queued) return;
3395    it->queued = EINA_TRUE;
3396    wd->queue = eina_list_append(wd->queue, it);
3397    while ((wd->queue) && ((!wd->blocks) || (!wd->blocks->next)))
3398      {
3399         if (wd->queue_idler)
3400           {
3401              ecore_idler_del(wd->queue_idler);
3402              wd->queue_idler = NULL;
3403           }
3404         _queue_process(wd, 0);
3405      }
3406    if (!wd->queue_idler) wd->queue_idler = ecore_idler_add(_item_idler, wd);
3407 }
3408
3409 /**
3410  * Append item to the end of the genlist
3411  *
3412  * This appends the given item to the end of the list or the end of
3413  * the children if the parent is given.
3414  *
3415  * @param obj The genlist object
3416  * @param itc The item class for the item
3417  * @param data The item data
3418  * @param parent The parent item, or NULL if none
3419  * @param flags Item flags
3420  * @param func Convenience function called when item selected
3421  * @param func_data Data passed to @p func above.
3422  * @return A handle to the item added or NULL if not possible
3423  *
3424  * @ingroup Genlist
3425  */
3426 EAPI Elm_Genlist_Item *
3427 elm_genlist_item_append(Evas_Object                  *obj,
3428                         const Elm_Genlist_Item_Class *itc,
3429                         const void                   *data,
3430                         Elm_Genlist_Item             *parent,
3431                         Elm_Genlist_Item_Flags        flags,
3432                         Evas_Smart_Cb                 func,
3433                         const void                   *func_data)
3434 {
3435    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3436    Widget_Data *wd = elm_widget_data_get(obj);
3437    if (!wd) return NULL;
3438    Elm_Genlist_Item *it = _item_new(wd, itc, data, parent, flags, func,
3439                                     func_data);
3440    if (!it) return NULL;
3441    if (!it->parent)
3442      {
3443         if (flags & ELM_GENLIST_ITEM_GROUP)
3444           wd->group_items = eina_list_append(wd->group_items, it);
3445         wd->items = eina_inlist_append(wd->items, EINA_INLIST_GET(it));
3446         it->rel = NULL;
3447      }
3448    else
3449      {
3450         Elm_Genlist_Item *it2 = NULL;
3451         Eina_List *ll = eina_list_last(it->parent->items);
3452         if (ll) it2 = ll->data;
3453         it->parent->items = eina_list_append(it->parent->items, it);
3454         if (!it2) it2 = it->parent;
3455         if (it2->delete_me)
3456            it2 = elm_genlist_item_prev_get(it2);
3457         wd->items =
3458           eina_inlist_append_relative(wd->items, EINA_INLIST_GET(it),
3459                                       EINA_INLIST_GET(it2));
3460         it->rel = it2;
3461         it->rel->relcount++;
3462
3463         if (it->parent->flags & ELM_GENLIST_ITEM_GROUP)
3464           it->group_item = parent;
3465         else if (it->parent->group_item)
3466           it->group_item = it->parent->group_item;
3467      }
3468    it->before = EINA_FALSE;
3469    _item_queue(wd, it);
3470    return it;
3471 }
3472
3473 /**
3474  * Prepend item at start of the genlist
3475  *
3476  * This adds an item to the beginning of the list or beginning of the
3477  * children of the parent if given.
3478  *
3479  * @param obj The genlist object
3480  * @param itc The item class for the item
3481  * @param data The item data
3482  * @param parent The parent item, or NULL if none
3483  * @param flags Item flags
3484  * @param func Convenience function called when item selected
3485  * @param func_data Data passed to @p func above.
3486  * @return A handle to the item added or NULL if not possible
3487  *
3488  * @ingroup Genlist
3489  */
3490 EAPI Elm_Genlist_Item *
3491 elm_genlist_item_prepend(Evas_Object                  *obj,
3492                          const Elm_Genlist_Item_Class *itc,
3493                          const void                   *data,
3494                          Elm_Genlist_Item             *parent,
3495                          Elm_Genlist_Item_Flags        flags,
3496                          Evas_Smart_Cb                 func,
3497                          const void                   *func_data)
3498 {
3499    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3500    Widget_Data *wd = elm_widget_data_get(obj);
3501    if (!wd) return NULL;
3502    Elm_Genlist_Item *it = _item_new(wd, itc, data, parent, flags, func,
3503                                     func_data);
3504    if (!it) return NULL;
3505    if (!it->parent)
3506      {
3507         if (flags & ELM_GENLIST_ITEM_GROUP)
3508           wd->group_items = eina_list_prepend(wd->group_items, it);
3509         wd->items = eina_inlist_prepend(wd->items, EINA_INLIST_GET(it));
3510         it->rel = NULL;
3511      }
3512    else
3513      {
3514         Elm_Genlist_Item *it2 = NULL;
3515         Eina_List *ll = it->parent->items;
3516         if (ll) it2 = ll->data;
3517         it->parent->items = eina_list_prepend(it->parent->items, it);
3518         if (!it2) it2 = it->parent;
3519         if (it2->delete_me)
3520            it2 = elm_genlist_item_next_get(it2);
3521         wd->items =
3522           eina_inlist_prepend_relative(wd->items, EINA_INLIST_GET(it),
3523                                        EINA_INLIST_GET(it2));
3524         it->rel = it2;
3525         it->rel->relcount++;
3526      }
3527    it->before = EINA_TRUE;
3528    _item_queue(wd, it);
3529    return it;
3530 }
3531
3532 /**
3533  * Insert item before another in the genlist
3534  *
3535  * This inserts an item before another in the list. It will be in the
3536  * same tree level or group as the item it is inseted before.
3537  *
3538  * @param obj The genlist object
3539  * @param itc The item class for the item
3540  * @param data The item data
3541  * @param before The item to insert before
3542  * @param flags Item flags
3543  * @param func Convenience function called when item selected
3544  * @param func_data Data passed to @p func above.
3545  * @return A handle to the item added or NULL if not possible
3546  *
3547  * @ingroup Genlist
3548  */
3549 EAPI Elm_Genlist_Item *
3550 elm_genlist_item_insert_before(Evas_Object                  *obj,
3551                                const Elm_Genlist_Item_Class *itc,
3552                                const void                   *data,
3553                                Elm_Genlist_Item             *parent,
3554                                Elm_Genlist_Item             *before,
3555                                Elm_Genlist_Item_Flags        flags,
3556                                Evas_Smart_Cb                 func,
3557                                const void                   *func_data)
3558 {
3559    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3560    EINA_SAFETY_ON_NULL_RETURN_VAL(before, NULL);
3561    Widget_Data *wd = elm_widget_data_get(obj);
3562    if (!wd) return NULL;
3563    Elm_Genlist_Item *it = _item_new(wd, itc, data, parent, flags, func,
3564                                     func_data);
3565    if (!it) return NULL;
3566    if (it->parent)
3567      {
3568         it->parent->items = eina_list_prepend_relative(it->parent->items, it,
3569                                                        before);
3570      }
3571    wd->items = eina_inlist_prepend_relative(wd->items, EINA_INLIST_GET(it),
3572                                             EINA_INLIST_GET(before));
3573    it->rel = before;
3574    it->rel->relcount++;
3575    it->before = EINA_TRUE;
3576    _item_queue(wd, it);
3577    return it;
3578 }
3579
3580 /**
3581  * Insert an item after another in the genlst
3582  *
3583  * This inserts an item after another in the list. It will be in the
3584  * same tree level or group as the item it is inseted after.
3585  *
3586  * @param obj The genlist object
3587  * @param itc The item class for the item
3588  * @param data The item data
3589  * @param after The item to insert after
3590  * @param flags Item flags
3591  * @param func Convenience function called when item selected
3592  * @param func_data Data passed to @p func above.
3593  * @return A handle to the item added or NULL if not possible
3594  *
3595  * @ingroup Genlist
3596  */
3597 EAPI Elm_Genlist_Item *
3598 elm_genlist_item_insert_after(Evas_Object                  *obj,
3599                               const Elm_Genlist_Item_Class *itc,
3600                               const void                   *data,
3601                               Elm_Genlist_Item             *parent,
3602                               Elm_Genlist_Item             *after,
3603                               Elm_Genlist_Item_Flags        flags,
3604                               Evas_Smart_Cb                 func,
3605                               const void                   *func_data)
3606 {
3607    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3608    EINA_SAFETY_ON_NULL_RETURN_VAL(after, NULL);
3609    Widget_Data *wd = elm_widget_data_get(obj);
3610    if (!wd) return NULL;
3611    Elm_Genlist_Item *it = _item_new(wd, itc, data, parent, flags, func,
3612                                     func_data);
3613    if (!it) return NULL;
3614    wd->items = eina_inlist_append_relative(wd->items, EINA_INLIST_GET(it),
3615                                            EINA_INLIST_GET(after));
3616    if (it->parent)
3617      {
3618         it->parent->items = eina_list_append_relative(it->parent->items, it,
3619                                                       after);
3620      }
3621    it->rel = after;
3622    it->rel->relcount++;
3623    it->before = EINA_FALSE;
3624    _item_queue(wd, it);
3625    return it;
3626 }
3627
3628 /**
3629  * Clear the genlist
3630  *
3631  * This clears all items in the list, leaving it empty.
3632  *
3633  * @param obj The genlist object
3634  *
3635  * @ingroup Genlist
3636  */
3637 EAPI void
3638 elm_genlist_clear(Evas_Object *obj)
3639 {
3640    ELM_CHECK_WIDTYPE(obj, widtype);
3641    Widget_Data *wd = elm_widget_data_get(obj);
3642    if (!wd) return;
3643    if (wd->walking > 0)
3644      {
3645         Elm_Genlist_Item *it;
3646
3647         wd->clear_me = EINA_TRUE;
3648         EINA_INLIST_FOREACH(wd->items, it)
3649           {
3650              it->delete_me = EINA_TRUE;
3651           }
3652         return;
3653      }
3654    while (wd->items)
3655      {
3656         Elm_Genlist_Item *it = ELM_GENLIST_ITEM_FROM_INLIST(wd->items);
3657         it->nocache = EINA_TRUE;
3658         it->highlighted = EINA_FALSE;
3659 #ifdef ANCHOR_ITEM
3660         if (wd->anchor_item == it)
3661           {
3662              wd->anchor_item = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
3663              if (!wd->anchor_item)
3664                wd->anchor_item =
3665                  ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
3666           }
3667 #endif
3668         wd->items = eina_inlist_remove(wd->items, wd->items);
3669         if (it->flags & ELM_GENLIST_ITEM_GROUP)
3670           it->wd->group_items = eina_list_remove(it->wd->group_items, it);
3671         elm_widget_item_pre_notify_del(it);
3672         if (it->effect_item_realized) _effect_item_unrealize(it);
3673         if (it->realized) _item_unrealize(it);
3674         if (((wd->clear_me) || (!it->delete_me)) && (it->itc->func.del))
3675           it->itc->func.del((void *)it->base.data, it->base.widget);
3676         if (it->long_timer) ecore_timer_del(it->long_timer);
3677         if (it->swipe_timer) ecore_timer_del(it->swipe_timer);
3678         elm_widget_item_del(it);
3679      }
3680    wd->clear_me = EINA_FALSE;
3681    wd->anchor_item = NULL;
3682    while (wd->blocks)
3683      {
3684         Item_Block *itb = (Item_Block *)(wd->blocks);
3685
3686         wd->blocks = eina_inlist_remove(wd->blocks, wd->blocks);
3687         if (itb->items) eina_list_free(itb->items);
3688         free(itb);
3689      }
3690    if (wd->calc_job)
3691      {
3692         ecore_job_del(wd->calc_job);
3693         wd->calc_job = NULL;
3694      }
3695    if (wd->queue_idler)
3696      {
3697         ecore_idler_del(wd->queue_idler);
3698         wd->queue_idler = NULL;
3699      }
3700    if (wd->must_recalc_idler)
3701      {
3702         ecore_idler_del(wd->must_recalc_idler);
3703         wd->must_recalc_idler = NULL;
3704      }
3705    if (wd->queue)
3706      {
3707         eina_list_free(wd->queue);
3708         wd->queue = NULL;
3709      }
3710    if (wd->selected)
3711      {
3712         eina_list_free(wd->selected);
3713         wd->selected = NULL;
3714      }
3715    if (wd->item_moving_effect_timer)
3716      {
3717         ecore_animator_del(wd->item_moving_effect_timer);
3718         wd->item_moving_effect_timer = NULL;
3719      }
3720    wd->show_item = NULL;
3721    wd->pan_x = 0;
3722    wd->pan_y = 0;
3723    wd->minw = 0;
3724    wd->minh = 0;
3725
3726    if (wd->alpha_bg)
3727       evas_object_del(wd->alpha_bg);
3728    wd->alpha_bg = NULL;
3729
3730    if (wd->pan_smart)
3731      {
3732         evas_object_size_hint_min_set(wd->pan_smart, wd->minw, wd->minh);
3733         evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
3734      }
3735    _sizing_eval(obj);
3736 }
3737
3738 /**
3739  * Enable or disable multi-select in the genlist
3740  *
3741  * This enables (EINA_TRUE) or disables (EINA_FALSE) multi-select in
3742  * the list. This allows more than 1 item to be selected.
3743  *
3744  * @param obj The genlist object
3745  * @param multi Multi-select enable/disable
3746  *
3747  * @ingroup Genlist
3748  */
3749 EAPI void
3750 elm_genlist_multi_select_set(Evas_Object *obj,
3751                              Eina_Bool    multi)
3752 {
3753    ELM_CHECK_WIDTYPE(obj, widtype);
3754    Widget_Data *wd = elm_widget_data_get(obj);
3755    if (!wd) return;
3756    wd->multi = multi;
3757 }
3758
3759 /**
3760  * Gets if multi-select in genlist is enable or disable
3761  *
3762  * @param obj The genlist object
3763  * @return Multi-select enable/disable
3764  * (EINA_TRUE = enabled/EINA_FALSE = disabled)
3765  *
3766  * @ingroup Genlist
3767  */
3768 EAPI Eina_Bool
3769 elm_genlist_multi_select_get(const Evas_Object *obj)
3770 {
3771    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
3772    Widget_Data *wd = elm_widget_data_get(obj);
3773    if (!wd) return EINA_FALSE;
3774    return wd->multi;
3775 }
3776
3777 /**
3778  * Get the selectd item in the genlist
3779  *
3780  * This gets the selected item in the list (if multi-select is enabled
3781  * only the first item in the list is selected - which is not very
3782  * useful, so see elm_genlist_selected_items_get() for when
3783  * multi-select is used).
3784  *
3785  * If no item is selected, NULL is returned.
3786  *
3787  * @param obj The genlist object
3788  * @return The selected item, or NULL if none.
3789  *
3790  * @ingroup Genlist
3791  */
3792 EAPI Elm_Genlist_Item *
3793 elm_genlist_selected_item_get(const Evas_Object *obj)
3794 {
3795    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3796    Widget_Data *wd = elm_widget_data_get(obj);
3797    if (!wd) return NULL;
3798    if (wd->selected) return wd->selected->data;
3799    return NULL;
3800 }
3801
3802 /**
3803  * Get a list of selected items in the genlist
3804  *
3805  * This returns a list of the selected items. This list pointer is
3806  * only valid so long as no items are selected or unselected (or
3807  * unselected implicitly by deletion). The list contains
3808  * Elm_Genlist_Item pointers.
3809  *
3810  * @param obj The genlist object
3811  * @return The list of selected items, nor NULL if none are selected.
3812  *
3813  * @ingroup Genlist
3814  */
3815 EAPI const Eina_List *
3816 elm_genlist_selected_items_get(const Evas_Object *obj)
3817 {
3818    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3819    Widget_Data *wd = elm_widget_data_get(obj);
3820    if (!wd) return NULL;
3821    return wd->selected;
3822 }
3823
3824 /**
3825  * Get a list of realized items in genlist
3826  *
3827  * This returns a list of the realized items in the genlist. The list
3828  * contains Elm_Genlist_Item pointers. The list must be freed by the
3829  * caller when done with eina_list_free(). The item pointers in the
3830  * list are only valid so long as those items are not deleted or the
3831  * genlist is not deleted.
3832  *
3833  * @param obj The genlist object
3834  * @return The list of realized items, nor NULL if none are realized.
3835  *
3836  * @ingroup Genlist
3837  */
3838 EAPI Eina_List *
3839 elm_genlist_realized_items_get(const Evas_Object *obj)
3840 {
3841    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3842    Widget_Data *wd = elm_widget_data_get(obj);
3843    Eina_List *list = NULL;
3844    Item_Block *itb;
3845    Eina_Bool done = EINA_FALSE;
3846    if (!wd) return NULL;
3847    EINA_INLIST_FOREACH(wd->blocks, itb)
3848      {
3849         if (itb->realized)
3850           {
3851              Eina_List *l;
3852              Elm_Genlist_Item *it;
3853
3854              done = 1;
3855              EINA_LIST_FOREACH(itb->items, l, it)
3856                {
3857                   if (it->realized) list = eina_list_append(list, it);
3858                }
3859           }
3860         else
3861           {
3862              if (done) break;
3863           }
3864      }
3865    return list;
3866 }
3867
3868 /**
3869  * Get the item that is at the x, y canvas coords
3870  *
3871  * This returns the item at the given coordinates (which are canvas
3872  * relative not object-relative). If an item is at that coordinate,
3873  * that item handle is returned, and if @p posret is not NULL, the
3874  * integer pointed to is set to a value of -1, 0 or 1, depending if
3875  * the coordinate is on the upper portion of that item (-1), on the
3876  * middle section (0) or on the lower part (1). If NULL is returned as
3877  * an item (no item found there), then posret may indicate -1 or 1
3878  * based if the coordinate is above or below all items respectively in
3879  * the genlist.
3880  *
3881  * @param it The item
3882  * @param x The input x coordinate
3883  * @param y The input y coordinate
3884  * @param posret The position relative to the item returned here
3885  * @return The item at the coordinates or NULL if none
3886  *
3887  * @ingroup Genlist
3888  */
3889 EAPI Elm_Genlist_Item *
3890 elm_genlist_at_xy_item_get(const Evas_Object *obj,
3891                            Evas_Coord         x,
3892                            Evas_Coord         y,
3893                            int               *posret)
3894 {
3895    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3896    Widget_Data *wd = elm_widget_data_get(obj);
3897    Evas_Coord ox, oy, ow, oh;
3898    Item_Block *itb;
3899    Evas_Coord lasty;
3900    if (!wd) return NULL;
3901    evas_object_geometry_get(wd->pan_smart, &ox, &oy, &ow, &oh);
3902    lasty = oy;
3903    EINA_INLIST_FOREACH(wd->blocks, itb)
3904      {
3905         Eina_List *l;
3906         Elm_Genlist_Item *it;
3907
3908         if (!ELM_RECTS_INTERSECT(ox + itb->x - itb->wd->pan_x,
3909                                  oy + itb->y - itb->wd->pan_y,
3910                                  itb->w, itb->h, x, y, 1, 1))
3911           continue;
3912         EINA_LIST_FOREACH(itb->items, l, it)
3913           {
3914              Evas_Coord itx, ity;
3915
3916              itx = ox + itb->x + it->x - itb->wd->pan_x;
3917              ity = oy + itb->y + it->y - itb->wd->pan_y;
3918              if (ELM_RECTS_INTERSECT(itx, ity, it->w, it->h, x, y, 1, 1))
3919                {
3920                   if (posret)
3921                     {
3922                        if (y <= (ity + (it->h / 4))) *posret = -1;
3923                        else if (y >= (ity + it->h - (it->h / 4)))
3924                          *posret = 1;
3925                        else *posret = 0;
3926                     }
3927                   return it;
3928                }
3929              lasty = ity + it->h;
3930           }
3931      }
3932    if (posret)
3933      {
3934         if (y > lasty) *posret = 1;
3935         else *posret = -1;
3936      }
3937    return NULL;
3938 }
3939
3940 /**
3941  * Get the first item in the genlist
3942  *
3943  * This returns the first item in the list.
3944  *
3945  * @param obj The genlist object
3946  * @return The first item, or NULL if none
3947  *
3948  * @ingroup Genlist
3949  */
3950 EAPI Elm_Genlist_Item *
3951 elm_genlist_first_item_get(const Evas_Object *obj)
3952 {
3953    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3954    Widget_Data *wd = elm_widget_data_get(obj);
3955    if (!wd) return NULL;
3956    if (!wd->items) return NULL;
3957    Elm_Genlist_Item *it = ELM_GENLIST_ITEM_FROM_INLIST(wd->items);
3958    while ((it) && (it->delete_me))
3959      it = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
3960    return it;
3961 }
3962
3963 /**
3964  * Get the last item in the genlist
3965  *
3966  * This returns the last item in the list.
3967  *
3968  * @return The last item, or NULL if none
3969  *
3970  * @ingroup Genlist
3971  */
3972 EAPI Elm_Genlist_Item *
3973 elm_genlist_last_item_get(const Evas_Object *obj)
3974 {
3975    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3976    Widget_Data *wd = elm_widget_data_get(obj);
3977    if (!wd) return NULL;
3978    if (!wd->items) return NULL;
3979    Elm_Genlist_Item *it = ELM_GENLIST_ITEM_FROM_INLIST(wd->items->last);
3980    while ((it) && (it->delete_me))
3981      it = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
3982    return it;
3983 }
3984
3985 /**
3986  * Get the next item in the genlist
3987  *
3988  * This returns the item after the item @p it.
3989  *
3990  * @param it The item
3991  * @return The item after @p it, or NULL if none
3992  *
3993  * @ingroup Genlist
3994  */
3995 EAPI Elm_Genlist_Item *
3996 elm_genlist_item_next_get(const Elm_Genlist_Item *it)
3997 {
3998    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
3999    while (it)
4000      {
4001         it = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
4002         if ((it) && (!it->delete_me)) break;
4003      }
4004    return (Elm_Genlist_Item *)it;
4005 }
4006
4007 /**
4008  * Get the previous item in the genlist
4009  *
4010  * This returns the item before the item @p it.
4011  *
4012  * @param it The item
4013  * @return The item before @p it, or NULL if none
4014  *
4015  * @ingroup Genlist
4016  */
4017 EAPI Elm_Genlist_Item *
4018 elm_genlist_item_prev_get(const Elm_Genlist_Item *it)
4019 {
4020    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
4021    while (it)
4022      {
4023         it = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
4024         if ((it) && (!it->delete_me)) break;
4025      }
4026    return (Elm_Genlist_Item *)it;
4027 }
4028
4029 /**
4030  * Get the genlist object from an item
4031  *
4032  * This returns the genlist object itself that an item belongs to.
4033  *
4034  * @param it The item
4035  * @return The genlist object
4036  *
4037  * @ingroup Genlist
4038  */
4039 EAPI Evas_Object *
4040 elm_genlist_item_genlist_get(const Elm_Genlist_Item *it)
4041 {
4042    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
4043    return it->base.widget;
4044 }
4045
4046 /**
4047  * Get the parent item of the given item
4048  *
4049  * This returns the parent item of the item @p it given.
4050  *
4051  * @param it The item
4052  * @return The parent of the item or NULL if none
4053  *
4054  * @ingroup Genlist
4055  */
4056 EAPI Elm_Genlist_Item *
4057 elm_genlist_item_parent_get(const Elm_Genlist_Item *it)
4058 {
4059    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
4060    return it->parent;
4061 }
4062
4063 /**
4064  * Clear all sub-items (children) of the given item
4065  *
4066  * This clears all items that are children (or their descendants) of the
4067  * given item @p it.
4068  *
4069  * @param it The item
4070  *
4071  * @ingroup Genlist
4072  */
4073 EAPI void
4074 elm_genlist_item_subitems_clear(Elm_Genlist_Item *it)
4075 {
4076    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4077    Elm_Genlist_Item *it2;
4078    Evas_Coord y, h;
4079
4080    if(!it->wd->effect_mode || !it->wd->move_effect_mode)
4081       _item_subitems_clear(it);
4082    else
4083      {
4084         if((!it->wd->item_moving_effect_timer) && (it->flags != ELM_GENLIST_ITEM_GROUP) &&
4085         it->wd->move_effect_mode != ELM_GENLIST_ITEM_MOVE_EFFECT_DELETE )
4086           {
4087              it->wd->expand_item = it;
4088              _item_flip_effect_show(it);
4089              evas_object_geometry_get(it->base.view, NULL, &y, NULL, &h);
4090              it->wd->expand_item_end = y + h;
4091
4092               it2= it;
4093              do {
4094                   it2 = elm_genlist_item_next_get(it2);
4095                   if(!it2) break;
4096              } while (it2->expanded_depth > it->expanded_depth);
4097              if(it2)
4098                 it->wd->expand_item_gap = it->wd->expand_item_end - it2->old_scrl_y;
4099              else
4100                 it->wd->expand_item_gap = 0;
4101
4102              evas_object_raise(it->wd->alpha_bg);
4103              evas_object_show(it->wd->alpha_bg);
4104
4105              it->wd->start_time = current_time_get();
4106              it->wd->item_moving_effect_timer = ecore_animator_add(_item_moving_effect_timer_cb, it->wd);
4107           }
4108         else
4109            _item_subitems_clear(it);
4110      }
4111 }
4112
4113 /**
4114  * Set the selected state of an item
4115  *
4116  * This sets the selected state (1 selected, 0 not selected) of the given
4117  * item @p it.
4118  *
4119  * @param it The item
4120  * @param selected The selected state
4121  *
4122  * @ingroup Genlist
4123  */
4124 EAPI void
4125 elm_genlist_item_selected_set(Elm_Genlist_Item *it,
4126                               Eina_Bool         selected)
4127 {
4128    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4129    Widget_Data *wd = elm_widget_data_get(it->base.widget);
4130    if (!wd) return;
4131    if (it->delete_me) return;
4132    selected = !!selected;
4133    if (it->selected == selected) return;
4134
4135    if (selected)
4136      {
4137         if (!wd->multi)
4138           {
4139              while (wd->selected)
4140                _item_unselect(wd->selected->data);
4141           }
4142         _item_highlight(it);
4143         _item_select(it);
4144      }
4145    else
4146      _item_unselect(it);
4147 }
4148
4149 /**
4150  * Get the selected state of an item
4151  *
4152  * This gets the selected state of an item (1 selected, 0 not selected).
4153  *
4154  * @param it The item
4155  * @return The selected state
4156  *
4157  * @ingroup Genlist
4158  */
4159 EAPI Eina_Bool
4160 elm_genlist_item_selected_get(const Elm_Genlist_Item *it)
4161 {
4162    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
4163    return it->selected;
4164 }
4165
4166 /**
4167  * Sets the expanded state of an item (if it's a parent)
4168  *
4169  * This expands or contracts a parent item (thus showing or hiding the
4170  * children).
4171  *
4172  * @param it The item
4173  * @param expanded The expanded state (1 expanded, 0 not expanded).
4174  *
4175  * @ingroup Genlist
4176  */
4177 EAPI void
4178 elm_genlist_item_expanded_set(Elm_Genlist_Item *it,
4179                               Eina_Bool         expanded)
4180 {
4181    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4182    if (it->expanded == expanded) return;
4183    it->expanded = expanded;
4184    it->wd->expand_item = it;
4185
4186    if(it->wd->effect_mode && !it->wd->alpha_bg)
4187       it->wd->alpha_bg = _create_tray_alpha_bg(it->base.widget);
4188
4189    if (it->expanded)
4190      {
4191         it->wd->auto_scrolled = EINA_FALSE;
4192         it->wd->move_effect_mode = ELM_GENLIST_ITEM_MOVE_EFFECT_EXPAND;
4193         if (it->realized)
4194           edje_object_signal_emit(it->base.view, "elm,state,expanded", "elm");
4195         evas_object_smart_callback_call(it->base.widget, "expanded", it);
4196      }
4197    else
4198      {
4199         it->wd->contracting = EINA_TRUE;
4200         it->wd->move_effect_mode = ELM_GENLIST_ITEM_MOVE_EFFECT_CONTRACT;
4201         if (it->realized)
4202           edje_object_signal_emit(it->base.view, "elm,state,contracted", "elm");
4203         evas_object_smart_callback_call(it->base.widget, "contracted", it);
4204      }
4205 }
4206
4207 /**
4208  * Get the expanded state of an item
4209  *
4210  * This gets the expanded state of an item
4211  *
4212  * @param it The item
4213  * @return Thre expanded state
4214  *
4215  * @ingroup Genlist
4216  */
4217 EAPI Eina_Bool
4218 elm_genlist_item_expanded_get(const Elm_Genlist_Item *it)
4219 {
4220    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
4221    return it->expanded;
4222 }
4223
4224 /**
4225  * Get the depth of expanded item
4226  *
4227  * @param it The genlist item object
4228  * @return The depth of expanded item
4229  *
4230  * @ingroup Genlist
4231  */
4232 EAPI int
4233 elm_genlist_item_expanded_depth_get(const Elm_Genlist_Item *it)
4234 {
4235    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, 0);
4236    return it->expanded_depth;
4237 }
4238
4239 /**
4240  * Sets the disabled state of an item.
4241  *
4242  * A disabled item cannot be selected or unselected. It will also
4243  * change appearance to appear disabled. This sets the disabled state
4244  * (1 disabled, 0 not disabled).
4245  *
4246  * @param it The item
4247  * @param disabled The disabled state
4248  *
4249  * @ingroup Genlist
4250  */
4251 EAPI void
4252 elm_genlist_item_disabled_set(Elm_Genlist_Item *it,
4253                               Eina_Bool         disabled)
4254 {
4255    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4256    if (it->disabled == disabled) return;
4257    if (it->delete_me) return;
4258    it->disabled = disabled;
4259    if (it->realized)
4260      {
4261         if (it->disabled)
4262           edje_object_signal_emit(it->base.view, "elm,state,disabled", "elm");
4263         else
4264           edje_object_signal_emit(it->base.view, "elm,state,enabled", "elm");
4265      }
4266 }
4267
4268 /**
4269  * Get the disabled state of an item
4270  *
4271  * This gets the disabled state of the given item.
4272  *
4273  * @param it The item
4274  * @return The disabled state
4275  *
4276  * @ingroup Genlist
4277  */
4278 EAPI Eina_Bool
4279 elm_genlist_item_disabled_get(const Elm_Genlist_Item *it)
4280 {
4281    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
4282    if (it->delete_me) return EINA_FALSE;
4283    return it->disabled;
4284 }
4285
4286 /**
4287  * Sets the display only state of an item.
4288  *
4289  * A display only item cannot be selected or unselected. It is for
4290  * display only and not selecting or otherwise clicking, dragging
4291  * etc. by the user, thus finger size rules will not be applied to
4292  * this item.
4293  *
4294  * @param it The item
4295  * @param display_only The display only state
4296  *
4297  * @ingroup Genlist
4298  */
4299 EAPI void
4300 elm_genlist_item_display_only_set(Elm_Genlist_Item *it,
4301                                   Eina_Bool         display_only)
4302 {
4303    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4304    if (it->display_only == display_only) return;
4305    if (it->delete_me) return;
4306    it->display_only = display_only;
4307    it->mincalcd = EINA_FALSE;
4308    it->updateme = EINA_TRUE;
4309    if (it->block) it->block->updateme = EINA_TRUE;
4310    if (it->wd->update_job) ecore_job_del(it->wd->update_job);
4311    it->wd->update_job = ecore_job_add(_update_job, it->wd);
4312 }
4313
4314 /**
4315  * Get the display only state of an item
4316  *
4317  * This gets the display only state of the given item.
4318  *
4319  * @param it The item
4320  * @return The display only state
4321  *
4322  * @ingroup Genlist
4323  */
4324 EAPI Eina_Bool
4325 elm_genlist_item_display_only_get(const Elm_Genlist_Item *it)
4326 {
4327    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
4328    if (it->delete_me) return EINA_FALSE;
4329    return it->display_only;
4330 }
4331
4332 /**
4333  * Show the given item
4334  *
4335  * This causes genlist to jump to the given item @p it and show it (by
4336  * scrolling), if it is not fully visible.
4337  *
4338  * @param it The item
4339  *
4340  * @ingroup Genlist
4341  */
4342 EAPI void
4343 elm_genlist_item_show(Elm_Genlist_Item *it)
4344 {
4345    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4346    Evas_Coord gith = 0;
4347    if (it->delete_me) return;
4348    if ((it->queued) || (!it->mincalcd))
4349      {
4350         it->wd->show_item = it;
4351         it->wd->bring_in = EINA_TRUE;
4352         it->showme = EINA_TRUE;
4353         return;
4354      }
4355    if (it->wd->show_item)
4356      {
4357         it->wd->show_item->showme = EINA_FALSE;
4358         it->wd->show_item = NULL;
4359      }
4360    if ((it->group_item) && (it->wd->pan_y > (it->y + it->block->y)))
4361      gith = it->group_item->h;
4362    elm_smart_scroller_child_region_show(it->wd->scr,
4363                                         it->x + it->block->x,
4364                                         it->y + it->block->y - gith,
4365                                         it->block->w, it->h);
4366 }
4367
4368 /**
4369  * Bring in the given item
4370  *
4371  * This causes genlist to jump to the given item @p it and show it (by
4372  * scrolling), if it is not fully visible. This may use animation to
4373  * do so and take a period of time
4374  *
4375  * @param it The item
4376  *
4377  * @ingroup Genlist
4378  */
4379 EAPI void
4380 elm_genlist_item_bring_in(Elm_Genlist_Item *it)
4381 {
4382    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4383    Evas_Coord gith = 0;
4384    if (it->delete_me) return;
4385    if ((it->queued) || (!it->mincalcd))
4386      {
4387         it->wd->show_item = it;
4388         it->wd->bring_in = EINA_TRUE;
4389         it->showme = EINA_TRUE;
4390         return;
4391      }
4392    if (it->wd->show_item)
4393      {
4394         it->wd->show_item->showme = EINA_FALSE;
4395         it->wd->show_item = NULL;
4396      }
4397    if ((it->group_item) && (it->wd->pan_y > (it->y + it->block->y)))
4398      gith = it->group_item->h;
4399    elm_smart_scroller_region_bring_in(it->wd->scr,
4400                                       it->x + it->block->x,
4401                                       it->y + it->block->y - gith,
4402                                       it->block->w, it->h);
4403 }
4404
4405 /**
4406  * Show the given item at the top
4407  *
4408  * This causes genlist to jump to the given item @p it and show it (by
4409  * scrolling), if it is not fully visible.
4410  *
4411  * @param it The item
4412  *
4413  * @ingroup Genlist
4414  */
4415 EAPI void
4416 elm_genlist_item_top_show(Elm_Genlist_Item *it)
4417 {
4418    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4419    Evas_Coord ow, oh;
4420    Evas_Coord gith = 0;
4421
4422    if (it->delete_me) return;
4423    if ((it->queued) || (!it->mincalcd))
4424      {
4425         it->wd->show_item = it;
4426         it->wd->bring_in = EINA_TRUE;
4427         it->showme = EINA_TRUE;
4428         return;
4429      }
4430    if (it->wd->show_item)
4431      {
4432         it->wd->show_item->showme = EINA_FALSE;
4433         it->wd->show_item = NULL;
4434      }
4435    evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh);
4436    if (it->group_item) gith = it->group_item->h;
4437    elm_smart_scroller_child_region_show(it->wd->scr,
4438                                         it->x + it->block->x,
4439                                         it->y + it->block->y - gith,
4440                                         it->block->w, oh);
4441 }
4442
4443 /**
4444  * Bring in the given item at the top
4445  *
4446  * This causes genlist to jump to the given item @p it and show it (by
4447  * scrolling), if it is not fully visible. This may use animation to
4448  * do so and take a period of time
4449  *
4450  * @param it The item
4451  *
4452  * @ingroup Genlist
4453  */
4454 EAPI void
4455 elm_genlist_item_top_bring_in(Elm_Genlist_Item *it)
4456 {
4457    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4458    Evas_Coord ow, oh;
4459    Evas_Coord gith = 0;
4460
4461    if (it->delete_me) return;
4462    if ((it->queued) || (!it->mincalcd))
4463      {
4464         it->wd->show_item = it;
4465         it->wd->bring_in = EINA_TRUE;
4466         it->showme = EINA_TRUE;
4467         return;
4468      }
4469    if (it->wd->show_item)
4470      {
4471         it->wd->show_item->showme = EINA_FALSE;
4472         it->wd->show_item = NULL;
4473      }
4474    evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh);
4475    if (it->group_item) gith = it->group_item->h;
4476    elm_smart_scroller_region_bring_in(it->wd->scr,
4477                                       it->x + it->block->x,
4478                                       it->y + it->block->y - gith,
4479                                       it->block->w, oh);
4480 }
4481
4482 /**
4483  * Show the given item at the middle
4484  *
4485  * This causes genlist to jump to the given item @p it and show it (by
4486  * scrolling), if it is not fully visible.
4487  *
4488  * @param it The item
4489  *
4490  * @ingroup Genlist
4491  */
4492 EAPI void
4493 elm_genlist_item_middle_show(Elm_Genlist_Item *it)
4494 {
4495    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4496    Evas_Coord ow, oh;
4497
4498    if (it->delete_me) return;
4499    if ((it->queued) || (!it->mincalcd))
4500      {
4501         it->wd->show_item = it;
4502         it->wd->bring_in = EINA_TRUE;
4503         it->showme = EINA_TRUE;
4504         return;
4505      }
4506    if (it->wd->show_item)
4507      {
4508         it->wd->show_item->showme = EINA_FALSE;
4509         it->wd->show_item = NULL;
4510      }
4511    evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh);
4512    elm_smart_scroller_child_region_show(it->wd->scr,
4513                                         it->x + it->block->x,
4514                                         it->y + it->block->y - oh / 2 +
4515                                         it->h / 2, it->block->w, oh);
4516 }
4517
4518 /**
4519  * Bring in the given item at the middle
4520  *
4521  * This causes genlist to jump to the given item @p it and show it (by
4522  * scrolling), if it is not fully visible. This may use animation to
4523  * do so and take a period of time
4524  *
4525  * @param it The item
4526  *
4527  * @ingroup Genlist
4528  */
4529 EAPI void
4530 elm_genlist_item_middle_bring_in(Elm_Genlist_Item *it)
4531 {
4532    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4533    Evas_Coord ow, oh;
4534
4535    if (it->delete_me) return;
4536    if ((it->queued) || (!it->mincalcd))
4537      {
4538         it->wd->show_item = it;
4539         it->wd->bring_in = EINA_TRUE;
4540         it->showme = EINA_TRUE;
4541         return;
4542      }
4543    if (it->wd->show_item)
4544      {
4545         it->wd->show_item->showme = EINA_FALSE;
4546         it->wd->show_item = NULL;
4547      }
4548    evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh);
4549    elm_smart_scroller_region_bring_in(it->wd->scr,
4550                                       it->x + it->block->x,
4551                                       it->y + it->block->y - oh / 2 + it->h / 2,
4552                                       it->block->w, oh);
4553 }
4554
4555 /**
4556  * Delete a given item
4557  *
4558  * This deletes the item from genlist and calls the genlist item del
4559  * class callback defined in the item class, if it is set. This clears all
4560  * subitems if it is a tree.
4561  *
4562  * @param it The item
4563  *
4564  * @ingroup Genlist
4565  */
4566 EAPI void
4567 elm_genlist_item_del(Elm_Genlist_Item *it)
4568 {
4569    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4570    if ((it->relcount > 0) || (it->walking > 0))
4571      {
4572         elm_widget_item_pre_notify_del(it);
4573         elm_genlist_item_subitems_clear(it);
4574         it->delete_me = EINA_TRUE;
4575         if (it->wd->show_item == it) it->wd->show_item = NULL;
4576         if (it->selected)
4577           it->wd->selected = eina_list_remove(it->wd->selected,
4578                                               it);
4579         if (it->block)
4580           {
4581              if (it->realized) _item_unrealize(it);
4582              if (it->effect_item_realized) _effect_item_unrealize(it);
4583              it->block->changed = EINA_TRUE;
4584              if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
4585              it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
4586           }
4587         if (it->itc->func.del)
4588           it->itc->func.del((void *)it->base.data, it->base.widget);
4589         return;
4590      }
4591    _item_del(it);
4592 }
4593
4594 /**
4595  * Set the data item from the genlist item
4596  *
4597  * This set the data value passed on the elm_genlist_item_append() and
4598  * related item addition calls. This function will also call
4599  * elm_genlist_item_update() so the item will be updated to reflect the
4600  * new data.
4601  *
4602  * @param it The item
4603  * @param data The new data pointer to set
4604  *
4605  * @ingroup Genlist
4606  */
4607 EAPI void
4608 elm_genlist_item_data_set(Elm_Genlist_Item *it,
4609                           const void       *data)
4610 {
4611    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4612    elm_widget_item_data_set(it, data);
4613    elm_genlist_item_update(it);
4614 }
4615
4616 /**
4617  * Get the data item from the genlist item
4618  *
4619  * This returns the data value passed on the elm_genlist_item_append()
4620  * and related item addition calls and elm_genlist_item_data_set().
4621  *
4622  * @param it The item
4623  * @return The data pointer provided when created
4624  *
4625  * @ingroup Genlist
4626  */
4627 EAPI void *
4628 elm_genlist_item_data_get(const Elm_Genlist_Item *it)
4629 {
4630    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
4631    return elm_widget_item_data_get(it);
4632 }
4633
4634 /**
4635  * Tells genlist to "orphan" icons fetchs by the item class
4636  *
4637  * This instructs genlist to release references to icons in the item,
4638  * meaning that they will no longer be managed by genlist and are
4639  * floating "orphans" that can be re-used elsewhere if the user wants
4640  * to.
4641  *
4642  * @param it The item
4643  *
4644  * @ingroup Genlist
4645  */
4646 EAPI void
4647 elm_genlist_item_icons_orphan(Elm_Genlist_Item *it)
4648 {
4649    Evas_Object *icon;
4650    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4651    EINA_LIST_FREE(it->icon_objs, icon)
4652      {
4653         elm_widget_sub_object_del(it->base.widget, icon);
4654         evas_object_smart_member_del(icon);
4655         evas_object_hide(icon);
4656      }
4657 }
4658
4659 /**
4660  * Get the real evas object of the genlist item
4661  *
4662  * This returns the actual evas object used for the specified genlist
4663  * item. This may be NULL as it may not be created, and may be deleted
4664  * at any time by genlist. Do not modify this object (move, resize,
4665  * show, hide etc.) as genlist is controlling it. This function is for
4666  * querying, emitting custom signals or hooking lower level callbacks
4667  * for events. Do not delete this object under any circumstances.
4668  *
4669  * @param it The item
4670  * @return The object pointer
4671  *
4672  * @ingroup Genlist
4673  */
4674 EAPI const Evas_Object *
4675 elm_genlist_item_object_get(const Elm_Genlist_Item *it)
4676 {
4677    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
4678    return it->base.view;
4679 }
4680
4681 /**
4682  * Update the contents of an item
4683  *
4684  * This updates an item by calling all the item class functions again
4685  * to get the icons, labels and states. Use this when the original
4686  * item data has changed and the changes are desired to be reflected.
4687  *
4688  * @param it The item
4689  *
4690  * @ingroup Genlist
4691  */
4692 EAPI void
4693 elm_genlist_item_update(Elm_Genlist_Item *it)
4694 {
4695    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4696    if (!it->block) return;
4697    if (it->delete_me) return;
4698    it->mincalcd = EINA_FALSE;
4699    it->updateme = EINA_TRUE;
4700    it->block->updateme = EINA_TRUE;
4701    if (it->wd->update_job) ecore_job_del(it->wd->update_job);
4702    it->wd->update_job = ecore_job_add(_update_job, it->wd);
4703 }
4704
4705 /**
4706  * Update the item class of an item
4707  *
4708  * @param it The item
4709  * @parem itc The item class for the item
4710  *
4711  * @ingroup Genlist
4712  */
4713 EAPI void
4714 elm_genlist_item_item_class_update(Elm_Genlist_Item             *it,
4715                                    const Elm_Genlist_Item_Class *itc)
4716 {
4717    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4718    if (!it->block) return;
4719    EINA_SAFETY_ON_NULL_RETURN(itc);
4720    if (it->delete_me) return;
4721    it->itc = itc;
4722    it->nocache = EINA_TRUE;
4723    elm_genlist_item_update(it);
4724 }
4725
4726 static Evas_Object *
4727 _elm_genlist_item_label_create(void        *data,
4728                                Evas_Object *obj,
4729                                void *item   __UNUSED__)
4730 {
4731    Evas_Object *label = elm_label_add(obj);
4732    if (!label)
4733      return NULL;
4734    elm_object_style_set(label, "tooltip");
4735    elm_label_label_set(label, data);
4736    return label;
4737 }
4738
4739 static void
4740 _elm_genlist_item_label_del_cb(void            *data,
4741                                Evas_Object *obj __UNUSED__,
4742                                void *event_info __UNUSED__)
4743 {
4744    eina_stringshare_del(data);
4745 }
4746
4747 /**
4748  * Set the text to be shown in the genlist item.
4749  *
4750  * @param item Target item
4751  * @param text The text to set in the content
4752  *
4753  * Setup the text as tooltip to object. The item can have only one
4754  * tooltip, so any previous tooltip data is removed.
4755  *
4756  * @ingroup Genlist
4757  */
4758 EAPI void
4759 elm_genlist_item_tooltip_text_set(Elm_Genlist_Item *item,
4760                                   const char       *text)
4761 {
4762    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
4763    text = eina_stringshare_add(text);
4764    elm_genlist_item_tooltip_content_cb_set(item, _elm_genlist_item_label_create,
4765                                            text,
4766                                            _elm_genlist_item_label_del_cb);
4767 }
4768
4769 /**
4770  * Set the content to be shown in the tooltip item
4771  *
4772  * Setup the tooltip to item. The item can have only one tooltip, so
4773  * any previous tooltip data is removed. @p func(with @p data) will be
4774  * called every time that need to show the tooltip and it should return a
4775  * valid Evas_Object. This object is then managed fully by tooltip
4776  * system and is deleted when the tooltip is gone.
4777  *
4778  * @param item the genlist item being attached by a tooltip.
4779  * @param func the function used to create the tooltip contents.
4780  * @param data what to provide to @a func as callback data/context.
4781  * @param del_cb called when data is not needed anymore, either when
4782  *        another callback replaces @func, the tooltip is unset with
4783  *        elm_genlist_item_tooltip_unset() or the owner @a item
4784  *        dies. This callback receives as the first parameter the
4785  *        given @a data, and @c event_info is the item.
4786  *
4787  * @ingroup Genlist
4788  */
4789 EAPI void
4790 elm_genlist_item_tooltip_content_cb_set(Elm_Genlist_Item           *item,
4791                                         Elm_Tooltip_Item_Content_Cb func,
4792                                         const void                 *data,
4793                                         Evas_Smart_Cb               del_cb)
4794 {
4795    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_GOTO(item, error);
4796
4797    if ((item->tooltip.content_cb == func) && (item->tooltip.data == data))
4798      return;
4799
4800    if (item->tooltip.del_cb)
4801      item->tooltip.del_cb((void *)item->tooltip.data,
4802                           item->base.widget, item);
4803
4804    item->tooltip.content_cb = func;
4805    item->tooltip.data = data;
4806    item->tooltip.del_cb = del_cb;
4807
4808    if (item->base.view)
4809      {
4810         elm_widget_item_tooltip_content_cb_set(item,
4811                                                item->tooltip.content_cb,
4812                                                item->tooltip.data, NULL);
4813         elm_widget_item_tooltip_style_set(item, item->tooltip.style);
4814      }
4815
4816    return;
4817
4818 error:
4819    if (del_cb) del_cb((void *)data, NULL, NULL);
4820 }
4821
4822 /**
4823  * Unset tooltip from item
4824  *
4825  * @param item genlist item to remove previously set tooltip.
4826  *
4827  * Remove tooltip from item. The callback provided as del_cb to
4828  * elm_genlist_item_tooltip_content_cb_set() will be called to notify
4829  * it is not used anymore.
4830  *
4831  * @see elm_genlist_item_tooltip_content_cb_set()
4832  *
4833  * @ingroup Genlist
4834  */
4835 EAPI void
4836 elm_genlist_item_tooltip_unset(Elm_Genlist_Item *item)
4837 {
4838    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
4839    if ((item->base.view) && (item->tooltip.content_cb))
4840      elm_widget_item_tooltip_unset(item);
4841
4842    if (item->tooltip.del_cb)
4843      item->tooltip.del_cb((void *)item->tooltip.data, item->base.widget, item);
4844    item->tooltip.del_cb = NULL;
4845    item->tooltip.content_cb = NULL;
4846    item->tooltip.data = NULL;
4847    if (item->tooltip.style)
4848      elm_genlist_item_tooltip_style_set(item, NULL);
4849 }
4850
4851 /**
4852  * Sets a different style for this item tooltip.
4853  *
4854  * @note before you set a style you should define a tooltip with
4855  *       elm_genlist_item_tooltip_content_cb_set() or
4856  *       elm_genlist_item_tooltip_text_set()
4857  *
4858  * @param item genlist item with tooltip already set.
4859  * @param style the theme style to use (default, transparent, ...)
4860  *
4861  * @ingroup Genlist
4862  */
4863 EAPI void
4864 elm_genlist_item_tooltip_style_set(Elm_Genlist_Item *item,
4865                                    const char       *style)
4866 {
4867    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
4868    eina_stringshare_replace(&item->tooltip.style, style);
4869    if (item->base.view) elm_widget_item_tooltip_style_set(item, style);
4870 }
4871
4872 /**
4873  * Get the style for this item tooltip.
4874  *
4875  * @param item genlist item with tooltip already set.
4876  * @return style the theme style in use, defaults to "default". If the
4877  *         object does not have a tooltip set, then NULL is returned.
4878  *
4879  * @ingroup Genlist
4880  */
4881 EAPI const char *
4882 elm_genlist_item_tooltip_style_get(const Elm_Genlist_Item *item)
4883 {
4884    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
4885    return item->tooltip.style;
4886 }
4887
4888 /**
4889  * Set the cursor to be shown when mouse is over the genlist item
4890  *
4891  * @param item Target item
4892  * @param cursor the cursor name to be used.
4893  *
4894  * @see elm_object_cursor_set()
4895  * @ingroup Genlist
4896  */
4897 EAPI void
4898 elm_genlist_item_cursor_set(Elm_Genlist_Item *item,
4899                             const char       *cursor)
4900 {
4901    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
4902    eina_stringshare_replace(&item->mouse_cursor, cursor);
4903    if (item->base.view) elm_widget_item_cursor_set(item, cursor);
4904 }
4905
4906 /**
4907  * Get the cursor to be shown when mouse is over the genlist item
4908  *
4909  * @param item genlist item with cursor already set.
4910  * @return the cursor name.
4911  *
4912  * @ingroup Genlist
4913  */
4914 EAPI const char *
4915 elm_genlist_item_cursor_get(const Elm_Genlist_Item *item)
4916 {
4917    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
4918    return elm_widget_item_cursor_get(item);
4919 }
4920
4921 /**
4922  * Unset the cursor to be shown when mouse is over the genlist item
4923  *
4924  * @param item Target item
4925  *
4926  * @see elm_object_cursor_unset()
4927  * @ingroup Genlist
4928  */
4929 EAPI void
4930 elm_genlist_item_cursor_unset(Elm_Genlist_Item *item)
4931 {
4932    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
4933    if (!item->mouse_cursor)
4934      return;
4935
4936    if (item->base.view)
4937      elm_widget_item_cursor_unset(item);
4938
4939    eina_stringshare_del(item->mouse_cursor);
4940    item->mouse_cursor = NULL;
4941 }
4942
4943 /**
4944  * Sets a different style for this item cursor.
4945  *
4946  * @note before you set a style you should define a cursor with
4947  *       elm_genlist_item_cursor_set()
4948  *
4949  * @param item genlist item with cursor already set.
4950  * @param style the theme style to use (default, transparent, ...)
4951  *
4952  * @ingroup Genlist
4953  */
4954 EAPI void
4955 elm_genlist_item_cursor_style_set(Elm_Genlist_Item *item,
4956                                   const char       *style)
4957 {
4958    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
4959    elm_widget_item_cursor_style_set(item, style);
4960 }
4961
4962 /**
4963  * Get the style for this item cursor.
4964  *
4965  * @param item genlist item with cursor already set.
4966  * @return style the theme style in use, defaults to "default". If the
4967  *         object does not have a cursor set, then NULL is returned.
4968  *
4969  * @ingroup Genlist
4970  */
4971 EAPI const char *
4972 elm_genlist_item_cursor_style_get(const Elm_Genlist_Item *item)
4973 {
4974    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
4975    return elm_widget_item_cursor_style_get(item);
4976 }
4977
4978 /**
4979  * Set if the cursor set should be searched on the theme or should use
4980  * the provided by the engine, only.
4981  *
4982  * @note before you set if should look on theme you should define a
4983  * cursor with elm_object_cursor_set(). By default it will only look
4984  * for cursors provided by the engine.
4985  *
4986  * @param item widget item with cursor already set.
4987  * @param engine_only boolean to define it cursors should be looked
4988  * only between the provided by the engine or searched on widget's
4989  * theme as well.
4990  *
4991  * @ingroup Genlist
4992  */
4993 EAPI void
4994 elm_genlist_item_cursor_engine_only_set(Elm_Genlist_Item *item,
4995                                         Eina_Bool         engine_only)
4996 {
4997    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
4998    elm_widget_item_cursor_engine_only_set(item, engine_only);
4999 }
5000
5001 /**
5002  * Get the cursor engine only usage for this item cursor.
5003  *
5004  * @param item widget item with cursor already set.
5005  * @return engine_only boolean to define it cursors should be looked
5006  * only between the provided by the engine or searched on widget's
5007  * theme as well. If the object does not have a cursor set, then
5008  * EINA_FALSE is returned.
5009  *
5010  * @ingroup Genlist
5011  */
5012 EAPI Eina_Bool
5013 elm_genlist_item_cursor_engine_only_get(const Elm_Genlist_Item *item)
5014 {
5015    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, EINA_FALSE);
5016    return elm_widget_item_cursor_engine_only_get(item);
5017 }
5018
5019 /**
5020  * This sets the horizontal stretching mode
5021  *
5022  * This sets the mode used for sizing items horizontally. Valid modes
5023  * are ELM_LIST_LIMIT and ELM_LIST_SCROLL. The default is
5024  * ELM_LIST_SCROLL. This mode means that if items are too wide to fit,
5025  * the scroller will scroll horizontally. Otherwise items are expanded
5026  * to fill the width of the viewport of the scroller. If it is
5027  * ELM_LIST_LIMIT, Items will be expanded to the viewport width and
5028  * limited to that size.
5029  *
5030  * @param obj The genlist object
5031  * @param mode The mode to use
5032  *
5033  * @ingroup Genlist
5034  */
5035 EAPI void
5036 elm_genlist_horizontal_mode_set(Evas_Object  *obj,
5037                                 Elm_List_Mode mode)
5038 {
5039    ELM_CHECK_WIDTYPE(obj, widtype);
5040    Widget_Data *wd = elm_widget_data_get(obj);
5041    if (!wd) return;
5042    if (wd->mode == mode) return;
5043    wd->mode = mode;
5044    _sizing_eval(obj);
5045 }
5046
5047 /**
5048  * Gets the horizontal stretching mode
5049  *
5050  * @param obj The genlist object
5051  * @return The mode to use
5052  * (ELM_LIST_LIMIT, ELM_LIST_SCROLL)
5053  *
5054  * @ingroup Genlist
5055  */
5056 EAPI Elm_List_Mode
5057 elm_genlist_horizontal_mode_get(const Evas_Object *obj)
5058 {
5059    ELM_CHECK_WIDTYPE(obj, widtype) ELM_LIST_LAST;
5060    Widget_Data *wd = elm_widget_data_get(obj);
5061    if (!wd) return ELM_LIST_LAST;
5062    return wd->mode;
5063 }
5064
5065 /**
5066  * Set the always select mode.
5067  *
5068  * Items will only call their selection func and callback when first
5069  * becoming selected. Any further clicks will do nothing, unless you
5070  * enable always select with elm_genlist_always_select_mode_set().
5071  * This means even if selected, every click will make the selected
5072  * callbacks be called.
5073  *
5074  * @param obj The genlist object
5075  * @param always_select The always select mode
5076  * (EINA_TRUE = on, EINA_FALSE = off)
5077  *
5078  * @ingroup Genlist
5079  */
5080 EAPI void
5081 elm_genlist_always_select_mode_set(Evas_Object *obj,
5082                                    Eina_Bool    always_select)
5083 {
5084    ELM_CHECK_WIDTYPE(obj, widtype);
5085    Widget_Data *wd = elm_widget_data_get(obj);
5086    if (!wd) return;
5087    wd->always_select = always_select;
5088 }
5089
5090 /**
5091  * Get the always select mode.
5092  *
5093  * @param obj The genlist object
5094  * @return The always select mode
5095  * (EINA_TRUE = on, EINA_FALSE = off)
5096  *
5097  * @ingroup Genlist
5098  */
5099 EAPI Eina_Bool
5100 elm_genlist_always_select_mode_get(const Evas_Object *obj)
5101 {
5102    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
5103    Widget_Data *wd = elm_widget_data_get(obj);
5104    if (!wd) return EINA_FALSE;
5105    return wd->always_select;
5106 }
5107
5108 /**
5109  * Set no select mode
5110  *
5111  * This will turn off the ability to select items entirely and they
5112  * will neither appear selected nor call selected callback functions.
5113  *
5114  * @param obj The genlist object
5115  * @param no_select The no select mode
5116  * (EINA_TRUE = on, EINA_FALSE = off)
5117  *
5118  * @ingroup Genlist
5119  */
5120 EAPI void
5121 elm_genlist_no_select_mode_set(Evas_Object *obj,
5122                                Eina_Bool    no_select)
5123 {
5124    ELM_CHECK_WIDTYPE(obj, widtype);
5125    Widget_Data *wd = elm_widget_data_get(obj);
5126    if (!wd) return;
5127    wd->no_select = no_select;
5128 }
5129
5130 /**
5131  * Gets no select mode
5132  *
5133  * @param obj The genlist object
5134  * @return The no select mode
5135  * (EINA_TRUE = on, EINA_FALSE = off)
5136  *
5137  * @ingroup Genlist
5138  */
5139 EAPI Eina_Bool
5140 elm_genlist_no_select_mode_get(const Evas_Object *obj)
5141 {
5142    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
5143    Widget_Data *wd = elm_widget_data_get(obj);
5144    if (!wd) return EINA_FALSE;
5145    return wd->no_select;
5146 }
5147
5148 /**
5149  * Set compress mode
5150  *
5151  * This will enable the compress mode where items are "compressed"
5152  * horizontally to fit the genlist scrollable viewport width. This is
5153  * special for genlist.  Do not rely on
5154  * elm_genlist_horizontal_mode_set() being set to ELM_LIST_COMPRESS to
5155  * work as genlist needs to handle it specially.
5156  *
5157  * @param obj The genlist object
5158  * @param compress The compress mode
5159  * (EINA_TRUE = on, EINA_FALSE = off)
5160  *
5161  * @ingroup Genlist
5162  */
5163 EAPI void
5164 elm_genlist_compress_mode_set(Evas_Object *obj,
5165                               Eina_Bool    compress)
5166 {
5167    ELM_CHECK_WIDTYPE(obj, widtype);
5168    Widget_Data *wd = elm_widget_data_get(obj);
5169    if (!wd) return;
5170    wd->compress = compress;
5171 }
5172
5173 /**
5174  * Get the compress mode
5175  *
5176  * @param obj The genlist object
5177  * @return The compress mode
5178  * (EINA_TRUE = on, EINA_FALSE = off)
5179  *
5180  * @ingroup Genlist
5181  */
5182 EAPI Eina_Bool
5183 elm_genlist_compress_mode_get(const Evas_Object *obj)
5184 {
5185    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
5186    Widget_Data *wd = elm_widget_data_get(obj);
5187    if (!wd) return EINA_FALSE;
5188    return wd->compress;
5189 }
5190
5191 /**
5192  * Set height-for-width mode
5193  *
5194  * With height-for-width mode the item width will be fixed (restricted
5195  * to a minimum of) to the list width when calculating its size in
5196  * order to allow the height to be calculated based on it. This allows,
5197  * for instance, text block to wrap lines if the Edje part is
5198  * configured with "text.min: 0 1".
5199  *
5200  * @note This mode will make list resize slower as it will have to
5201  *       recalculate every item height again whenever the list width
5202  *       changes!
5203  *
5204  * @note When height-for-width mode is enabled, it also enables
5205  *       compress mode (see elm_genlist_compress_mode_set()) and
5206  *       disables homogeneous (see elm_genlist_homogeneous_set()).
5207  *
5208  * @param obj The genlist object
5209  * @param setting The height-for-width mode (EINA_TRUE = on,
5210  * EINA_FALSE = off)
5211  *
5212  * @ingroup Genlist
5213  */
5214 EAPI void
5215 elm_genlist_height_for_width_mode_set(Evas_Object *obj,
5216                                       Eina_Bool    height_for_width)
5217 {
5218    ELM_CHECK_WIDTYPE(obj, widtype);
5219    Widget_Data *wd = elm_widget_data_get(obj);
5220    if (!wd) return;
5221    wd->height_for_width = !!height_for_width;
5222    if (wd->height_for_width)
5223      {
5224         elm_genlist_homogeneous_set(obj, EINA_FALSE);
5225         elm_genlist_compress_mode_set(obj, EINA_TRUE);
5226      }
5227 }
5228
5229 /**
5230  * Get the height-for-width mode
5231  *
5232  * @param obj The genlist object
5233  * @return The height-for-width mode (EINA_TRUE = on, EINA_FALSE =
5234  * off)
5235  *
5236  * @ingroup Genlist
5237  */
5238 EAPI Eina_Bool
5239 elm_genlist_height_for_width_mode_get(const Evas_Object *obj)
5240 {
5241    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
5242    Widget_Data *wd = elm_widget_data_get(obj);
5243    if (!wd) return EINA_FALSE;
5244    return wd->height_for_width;
5245 }
5246
5247 /**
5248  * Set bounce mode
5249  *
5250  * This will enable or disable the scroller bounce mode for the
5251  * genlist. See elm_scroller_bounce_set() for details
5252  *
5253  * @param obj The genlist object
5254  * @param h_bounce Allow bounce horizontally
5255  * @param v_bounce Allow bounce vertically
5256  *
5257  * @ingroup Genlist
5258  */
5259 EAPI void
5260 elm_genlist_bounce_set(Evas_Object *obj,
5261                        Eina_Bool    h_bounce,
5262                        Eina_Bool    v_bounce)
5263 {
5264    ELM_CHECK_WIDTYPE(obj, widtype);
5265    Widget_Data *wd = elm_widget_data_get(obj);
5266    if (!wd) return;
5267    elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
5268 }
5269
5270 /**
5271  * Get the bounce mode
5272  *
5273  * @param obj The genlist object
5274  * @param h_bounce Allow bounce horizontally
5275  * @param v_bounce Allow bounce vertically
5276  *
5277  * @ingroup Genlist
5278  */
5279 EAPI void
5280 elm_genlist_bounce_get(const Evas_Object *obj,
5281                        Eina_Bool         *h_bounce,
5282                        Eina_Bool         *v_bounce)
5283 {
5284    ELM_CHECK_WIDTYPE(obj, widtype);
5285    Widget_Data *wd = elm_widget_data_get(obj);
5286    if (!wd) return;
5287    elm_smart_scroller_bounce_allow_get(obj, h_bounce, v_bounce);
5288 }
5289
5290 /**
5291  * Set homogenous mode
5292  *
5293  * This will enable the homogeneous mode where items are of the same
5294  * height and width so that genlist may do the lazy-loading at its
5295  * maximum. This implies 'compressed' mode.
5296  *
5297  * @param obj The genlist object
5298  * @param homogeneous Assume the items within the genlist are of the
5299  * same height and width (EINA_TRUE = on, EINA_FALSE = off)
5300  *
5301  * @ingroup Genlist
5302  */
5303 EAPI void
5304 elm_genlist_homogeneous_set(Evas_Object *obj,
5305                             Eina_Bool    homogeneous)
5306 {
5307    ELM_CHECK_WIDTYPE(obj, widtype);
5308    Widget_Data *wd = elm_widget_data_get(obj);
5309    if (!wd) return;
5310    if (homogeneous) elm_genlist_compress_mode_set(obj, EINA_TRUE);
5311    wd->homogeneous = homogeneous;
5312 }
5313
5314 /**
5315  * Get the homogenous mode
5316  *
5317  * @param obj The genlist object
5318  * @return Assume the items within the genlist are of the same height
5319  * and width (EINA_TRUE = on, EINA_FALSE = off)
5320  *
5321  * @ingroup Genlist
5322  */
5323 EAPI Eina_Bool
5324 elm_genlist_homogeneous_get(const Evas_Object *obj)
5325 {
5326    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
5327    Widget_Data *wd = elm_widget_data_get(obj);
5328    if (!wd) return EINA_FALSE;
5329    return wd->homogeneous;
5330 }
5331
5332 /**
5333  * Set the maximum number of items within an item block
5334  *
5335  * This will configure the block count to tune to the target with
5336  * particular performance matrix.
5337  *
5338  * @param obj The genlist object
5339  * @param n   Maximum number of items within an item block
5340  *
5341  * @ingroup Genlist
5342  */
5343 EAPI void
5344 elm_genlist_block_count_set(Evas_Object *obj,
5345                             int          n)
5346 {
5347    ELM_CHECK_WIDTYPE(obj, widtype);
5348    Widget_Data *wd = elm_widget_data_get(obj);
5349    if (!wd) return;
5350    wd->max_items_per_block = n;
5351    wd->item_cache_max = wd->max_items_per_block * 2;
5352    _item_cache_clean(wd);
5353 }
5354
5355 /**
5356  * Get the maximum number of items within an item block
5357  *
5358  * @param obj The genlist object
5359  * @return Maximum number of items within an item block
5360  *
5361  * @ingroup Genlist
5362  */
5363 EAPI int
5364 elm_genlist_block_count_get(const Evas_Object *obj)
5365 {
5366    ELM_CHECK_WIDTYPE(obj, widtype) 0;
5367    Widget_Data *wd = elm_widget_data_get(obj);
5368    if (!wd) return 0;
5369    return wd->max_items_per_block;
5370 }
5371
5372 /**
5373  * Set the timeout in seconds for the longpress event
5374  *
5375  * @param obj The genlist object
5376  * @param timeout timeout in seconds
5377  *
5378  * @ingroup Genlist
5379  */
5380 EAPI void
5381 elm_genlist_longpress_timeout_set(Evas_Object *obj,
5382                                   double       timeout)
5383 {
5384    ELM_CHECK_WIDTYPE(obj, widtype);
5385    Widget_Data *wd = elm_widget_data_get(obj);
5386    if (!wd) return;
5387    wd->longpress_timeout = timeout;
5388 }
5389
5390 /**
5391  * Get the timeout in seconds for the longpress event
5392  *
5393  * @param obj The genlist object
5394  * @return timeout in seconds
5395  *
5396  * @ingroup Genlist
5397  */
5398 EAPI double
5399 elm_genlist_longpress_timeout_get(const Evas_Object *obj)
5400 {
5401    ELM_CHECK_WIDTYPE(obj, widtype) 0;
5402    Widget_Data *wd = elm_widget_data_get(obj);
5403    if (!wd) return 0;
5404    return wd->longpress_timeout;
5405 }
5406
5407 /**
5408  * Set the scrollbar policy
5409  *
5410  * This sets the scrollbar visibility policy for the given genlist
5411  * scroller. ELM_SMART_SCROLLER_POLICY_AUTO means the scrollbar is
5412  * made visible if it is needed, and otherwise kept hidden.
5413  * ELM_SMART_SCROLLER_POLICY_ON turns it on all the time, and
5414  * ELM_SMART_SCROLLER_POLICY_OFF always keeps it off. This applies
5415  * respectively for the horizontal and vertical scrollbars.
5416  *
5417  * @param obj The genlist object
5418  * @param policy_h Horizontal scrollbar policy
5419  * @param policy_v Vertical scrollbar policy
5420  *
5421  * @ingroup Genlist
5422  */
5423 EAPI void
5424 elm_genlist_scroller_policy_set(Evas_Object        *obj,
5425                                 Elm_Scroller_Policy policy_h,
5426                                 Elm_Scroller_Policy policy_v)
5427 {
5428    ELM_CHECK_WIDTYPE(obj, widtype);
5429    Widget_Data *wd = elm_widget_data_get(obj);
5430    if (!wd) return;
5431    if ((policy_h >= ELM_SCROLLER_POLICY_LAST) ||
5432        (policy_v >= ELM_SCROLLER_POLICY_LAST))
5433      return;
5434    if (wd->scr)
5435      elm_smart_scroller_policy_set(wd->scr, policy_h, policy_v);
5436 }
5437
5438 /**
5439  * Get the scrollbar policy
5440  *
5441  * @param obj The genlist object
5442  * @param policy_h Horizontal scrollbar policy
5443  * @param policy_v Vertical scrollbar policy
5444  *
5445  * @ingroup Genlist
5446  */
5447 EAPI void
5448 elm_genlist_scroller_policy_get(const Evas_Object   *obj,
5449                                 Elm_Scroller_Policy *policy_h,
5450                                 Elm_Scroller_Policy *policy_v)
5451 {
5452    ELM_CHECK_WIDTYPE(obj, widtype);
5453    Widget_Data *wd = elm_widget_data_get(obj);
5454    Elm_Smart_Scroller_Policy s_policy_h, s_policy_v;
5455    if ((!wd) || (!wd->scr)) return;
5456    elm_smart_scroller_policy_get(wd->scr, &s_policy_h, &s_policy_v);
5457    if (policy_h) *policy_h = (Elm_Scroller_Policy)s_policy_h;
5458    if (policy_v) *policy_v = (Elm_Scroller_Policy)s_policy_v;
5459 }
5460
5461 /****************************************************************************/
5462 /**
5463  * Set reorder mode
5464  *
5465  *
5466  * @param obj The genlist object
5467  * @param reorder_mode The reorder mode
5468  * (EINA_TRUE = on, EINA_FALSE = off)
5469  *
5470  * @ingroup Genlist
5471  */
5472 EAPI void
5473 elm_genlist_reorder_mode_set(Evas_Object *obj,
5474                              Eina_Bool    reorder_mode)
5475 {
5476    ELM_CHECK_WIDTYPE(obj, widtype);
5477    Widget_Data *wd = elm_widget_data_get(obj);
5478    if (!wd) return;
5479    wd->reorder_mode = reorder_mode;
5480 }
5481
5482 /**
5483  * Get the reorder mode
5484  *
5485  * @param obj The genlist object
5486  * @return The reorder mode
5487  * (EINA_TRUE = on, EINA_FALSE = off)
5488  *
5489  * @ingroup Genlist
5490  */
5491 EAPI Eina_Bool
5492 elm_genlist_reorder_mode_get(const Evas_Object *obj)
5493 {
5494    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
5495    Widget_Data *wd = elm_widget_data_get(obj);
5496    if (!wd) return EINA_FALSE;
5497    return wd->reorder_mode;
5498 }
5499
5500 EAPI void
5501 elm_genlist_item_move_after(Elm_Genlist_Item *it, Elm_Genlist_Item *after)
5502 {
5503    return;
5504 }
5505
5506 EAPI void
5507 elm_genlist_item_move_before(Elm_Genlist_Item *it, Elm_Genlist_Item *before)
5508 {
5509    return;
5510 }
5511
5512 static void
5513 _effect_item_move_after(Elm_Genlist_Item *it, Elm_Genlist_Item *after)
5514 {
5515    if (!it) return;
5516    if (!after) return;
5517
5518    if (it->wd->ed->ec->move)
5519       it->wd->ed->ec->move(it->base.widget, it, after, EINA_TRUE);
5520
5521 // printf("MOVE AFTER : %d  after = %d \n", (int)elm_genlist_item_data_get(it)+1, (int)elm_genlist_item_data_get(after)+1);
5522    it->wd->items = eina_inlist_remove(it->wd->items, EINA_INLIST_GET(it));
5523    it->wd->reorder_deleted = EINA_TRUE;
5524    _item_block_del(it);
5525
5526    it->wd->items = eina_inlist_append_relative(it->wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(after));
5527    it->rel = after;
5528    it->rel->relcount++;
5529    it->before = EINA_FALSE;
5530    _item_queue(it->wd, it);
5531 }
5532
5533 static void
5534 _effect_item_move_before(Elm_Genlist_Item *it, Elm_Genlist_Item *before)
5535 {
5536    if (!it) return;
5537    if (!before) return;
5538
5539    if (it->wd->ed->ec->move)
5540       it->wd->ed->ec->move(it->base.widget, it, before, EINA_FALSE);
5541
5542 //   printf("MOVE BEFORE : %d  before = %d \n", (int)elm_genlist_item_data_get(it)+1, (int)elm_genlist_item_data_get(before)+1);
5543    it->wd->items = eina_inlist_remove(it->wd->items, EINA_INLIST_GET(it));
5544    it->wd->reorder_deleted = EINA_TRUE;
5545    _item_block_del(it);
5546    it->wd->items = eina_inlist_prepend_relative(it->wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(before));
5547    it->rel = before;
5548    it->rel->relcount++;
5549    it->before = EINA_TRUE;
5550    _item_queue(it->wd, it);
5551 }
5552
5553 EAPI void
5554 elm_genlist_effect_set(const Evas_Object *obj, Eina_Bool emode)
5555 {
5556    ELM_CHECK_WIDTYPE(obj, widtype);
5557    Widget_Data *wd = elm_widget_data_get(obj);
5558    if (!wd) return;
5559    wd->effect_mode = emode;
5560    //   wd->point_rect = evas_object_rectangle_add(evas_object_evas_get(wd->obj));
5561    //   evas_object_resize(wd->point_rect, 10, 25);
5562    //   evas_object_color_set(wd->point_rect, 255, 0, 0, 130);
5563    //   evas_object_show(wd->point_rect);
5564    //   evas_object_hide(wd->point_rect);
5565 }
5566
5567 static Evas_Object*
5568 _create_tray_alpha_bg(const Evas_Object *obj)
5569 {
5570    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
5571    Widget_Data *wd = elm_widget_data_get(obj);
5572    if (!wd) return NULL;
5573
5574    Evas_Object *bg = NULL;
5575    Evas_Coord ox, oy, ow, oh;
5576
5577    evas_object_geometry_get(wd->pan_smart, &ox, &oy, &ow, &oh);
5578    bg  =  evas_object_rectangle_add(evas_object_evas_get(wd->obj));
5579    evas_object_color_set(bg,0,0,0,0);
5580    evas_object_resize(bg , ow, oh);
5581    evas_object_move(bg , ox, oy);
5582    evas_object_show(bg);
5583    evas_object_hide(bg);
5584    return bg ;
5585 }
5586
5587 static unsigned int
5588 current_time_get()
5589 {
5590    struct timeval timev;
5591
5592    gettimeofday(&timev, NULL);
5593    return ((timev.tv_sec * 1000) + ((timev.tv_usec) / 1000));
5594 }
5595
5596 // added for item moving animation.
5597 static Eina_Bool
5598 _item_moving_effect_timer_cb(void *data)
5599 {
5600    Widget_Data *wd = data;
5601    if (!wd) return EINA_FALSE;
5602    Item_Block *itb;
5603    Evas_Coord ox, oy, ow, oh, cvx, cvy, cvw, cvh;
5604    Elm_Genlist_Item *it, *it2;
5605    const Eina_List *l;
5606    double time = 0.4, t;
5607    int y, dy;
5608    Eina_Bool check, end = EINA_FALSE;
5609    //   static Eina_Bool first = EINA_TRUE;
5610    int in = 0;
5611
5612    t = ((0.0 > (t = current_time_get() - wd->start_time)) ? 0.0 : t) / 1000;
5613
5614    evas_object_geometry_get(wd->pan_smart, &ox, &oy, &ow, &oh);
5615    evas_output_viewport_get(evas_object_evas_get(wd->pan_smart), &cvx, &cvy, &cvw, &cvh);
5616    if (t > time) end = EINA_TRUE;
5617    EINA_INLIST_FOREACH(wd->blocks, itb)
5618      {
5619         itb->w = wd->minw;
5620         if (ELM_RECTS_INTERSECT(itb->x - wd->pan_x + ox,
5621                                 itb->y - wd->pan_y + oy,
5622                                 itb->w, itb->h,
5623                                 cvx, cvy, cvw, cvh))
5624           {
5625              EINA_LIST_FOREACH(itb->items, l, it)
5626                {
5627                   if (wd->move_effect_mode != ELM_GENLIST_ITEM_MOVE_EFFECT_DELETE)
5628                     {
5629                        it2 = it;
5630                        check = EINA_FALSE;
5631                        do {
5632                             if(it2->parent == wd->expand_item) check = EINA_TRUE;
5633                             it2 = it2->parent;
5634                        } while(it2);
5635                        if(check) continue;
5636                     }
5637                   dy = 0;
5638                   //printf(" s: %d %d ", oy, oh);
5639                   if(wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_EXPAND)
5640                      dy = it->scrl_y - it->old_scrl_y;
5641                   else if(wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_CONTRACT)
5642                     {
5643                        //                  printf("%d %d\n", it->old_scrl_y, wd->expand_item_end);
5644                        if(wd->expand_item_end < it->old_scrl_y)
5645                           dy = wd->expand_item_gap;
5646                     }
5647                   else if (wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_DELETE)
5648                     {
5649                         if (wd->expand_item_end < it->old_scrl_y)
5650                           dy = wd->expand_item_gap;
5651                     }
5652                   if (t <= time)
5653                      y = (1 * sin((t / time) * (M_PI / 2)) * dy);
5654                   else
5655                     {
5656                        end = EINA_TRUE;
5657                        y = dy;
5658                     }
5659
5660                   if (!it->old_scrl_y)
5661                      it->old_scrl_y  = it->scrl_y;
5662
5663
5664                   if (it->old_scrl_y + y < oy + oh)
5665                     {
5666                        if (!it->realized) _item_realize(it, in, 0);
5667                     }
5668                   if (wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_DELETE && it->old_scrl_y + y < it->scrl_y)
5669                      it->old_scrl_y = it->scrl_y - y;
5670                   in++;
5671
5672                  if (wd->move_effect_mode != ELM_GENLIST_ITEM_MOVE_EFFECT_DELETE ||
5673                        (wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_DELETE && it->old_scrl_y + y >= it->scrl_y))
5674                    {
5675                       if (wd->edit_mode) _effect_item_controls(it, it->scrl_x, it->old_scrl_y + y);
5676                       else
5677                        {
5678                            evas_object_resize(it->base.view, it->w, it->h);
5679                            evas_object_move(it->base.view, it->scrl_x, it->old_scrl_y + y);
5680                            evas_object_show(it->base.view);
5681                            evas_object_raise(it->base.view);
5682                        }
5683
5684                       if (it->group_item) evas_object_raise(it->group_item->base.view);
5685                    }
5686
5687                   if(wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_EXPAND)
5688                     {
5689                        it2 = elm_genlist_item_prev_get(it);
5690                        while(it2)
5691                          {
5692                             if((it2->scrl_y < it->old_scrl_y + y) && (it2->expanded_depth > it->expanded_depth))
5693                               {
5694                                  if(!it2->effect_done)
5695                                    {
5696                                       //edje_object_signal_emit(it2->base.view, "elm,state,expand_flip", "");
5697                                       evas_object_move(it2->base.view, it2->scrl_x, it2->scrl_y);
5698                                       evas_object_show(it2->base.view);
5699                                       it2->effect_done = EINA_TRUE;
5700                                    }
5701                                 // break;
5702                               }
5703                             it2 = elm_genlist_item_prev_get(it2);
5704                          }
5705                     }
5706                   else if(wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_CONTRACT)
5707                     {
5708                        it2 = elm_genlist_item_prev_get(it);
5709                        while(it2)
5710                          {
5711                             if((it2->scrl_y > it->old_scrl_y + y) && (it2->expanded_depth > it->expanded_depth))
5712                               {
5713                                  if(!it2->effect_done)
5714                                    {
5715                                       edje_object_signal_emit(it2->base.view, "elm,state,hide", "");
5716                                       it2->effect_done = EINA_TRUE;
5717                                    }
5718                               }
5719                             else
5720                                break;
5721                             it2 = elm_genlist_item_prev_get(it2);
5722                          }
5723                     }
5724                }
5725           }
5726      }
5727    //   first = EINA_FALSE;
5728    //   printf("\n");
5729    if (end)
5730      {
5731         if (wd->item_moving_effect_timer)
5732           {
5733              if(wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_CONTRACT)
5734                 _item_subitems_clear(wd->expand_item);
5735              EINA_INLIST_FOREACH(wd->blocks, itb)
5736                {
5737                   EINA_LIST_FOREACH(itb->items, l, it)
5738                     {
5739                        it->effect_done = EINA_TRUE;
5740                        it->old_scrl_y = it->scrl_y;
5741                     }
5742                }
5743           }
5744         //evas_render(evas_object_evas_get(wd->obj));
5745         wd->item_moving_effect_timer = NULL;
5746         //        first = EINA_TRUE;
5747
5748         _item_auto_scroll(wd);
5749         evas_object_lower(wd->alpha_bg);
5750         evas_object_hide(wd->alpha_bg);
5751         if (wd->calc_job) ecore_job_del(wd->calc_job);
5752         wd->calc_job = ecore_job_add(_calc_job, wd);
5753         elm_smart_scroller_bounce_animator_disabled_set(wd->scr, EINA_FALSE);
5754         wd->move_effect_mode = ELM_GENLIST_ITEM_MOVE_EFFECT_NONE;
5755
5756         evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
5757         evas_object_smart_callback_call(wd->obj, "effect_done", NULL);
5758         return ECORE_CALLBACK_CANCEL;
5759      }
5760    return ECORE_CALLBACK_RENEW;
5761 }
5762
5763 static void
5764 _emit_contract(Elm_Genlist_Item *it)
5765 {
5766    Elm_Genlist_Item *it2;
5767    Eina_List *l;
5768
5769    //   printf("%p is emited contract\n", it);
5770    edje_object_signal_emit(it->base.view, "elm,state,contract_flip", "");
5771    it->effect_done = EINA_FALSE;
5772
5773    EINA_LIST_FOREACH(it->items, l, it2)
5774       if(it2)
5775          _emit_contract(it2);
5776 }
5777
5778 // added for item moving animation.
5779 static int
5780 _item_flip_effect_show(Elm_Genlist_Item *it)
5781 {
5782    Elm_Genlist_Item *it2;
5783    Eina_List *l;
5784    Widget_Data *wd = it->wd;
5785    Eina_Bool check = EINA_FALSE;
5786
5787    it2 = elm_genlist_item_next_get(it);
5788    while(it2)
5789      {
5790         if(it2->expanded_depth <= it->expanded_depth) check = EINA_TRUE;
5791         it2 = elm_genlist_item_next_get(it2);
5792      }
5793    EINA_LIST_FOREACH(it->items, l, it2)
5794      {
5795         if (it2->parent && it == it2->parent)
5796           {
5797              if(wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_EXPAND)
5798                {
5799                   edje_object_signal_emit(it2->base.view, "flip_item", "");
5800                   if(check)
5801                      evas_object_move(it2->base.view, -9999, -9999);
5802                   else
5803                      evas_object_show(it2->base.view);
5804                }
5805              else if(wd->move_effect_mode == ELM_GENLIST_ITEM_MOVE_EFFECT_CONTRACT)
5806                 _emit_contract(it2);
5807           }
5808      }
5809
5810    return ECORE_CALLBACK_CANCEL;
5811 }
5812
5813 /*
5814 static void
5815 _elm_genlist_pinch_zoom_execute(Evas_Object *obj, Eina_Bool emode)
5816 {
5817    printf("!!! NOW FIXING \n");
5818 }
5819 */
5820
5821 /**
5822  * Set pinch zoom mode
5823  *
5824  * @param obj The genlist object
5825  * @param emode
5826  * (EINA_TRUE = pinch contract (zoom in), EINA_FALSE = pinch expand (zoom out)
5827  *
5828  * @ingroup Genlist
5829  */
5830 EAPI void
5831 elm_genlist_pinch_zoom_mode_set(Evas_Object *obj, Eina_Bool emode)
5832 {
5833    printf("!!! NOW FIXING \n");
5834 }
5835
5836 /**
5837  * Get pinch zoom mode
5838  *
5839  * @param obj The genlist object
5840  * @return The pinch mode
5841  * (EINA_TRUE = pinch contract (zoom in), EINA_FALSE = pinch expand (zoom out)
5842  *
5843  * @ingroup Genlist
5844  */
5845 EAPI Eina_Bool
5846 elm_genlist_pinch_zoom_mode_get(const Evas_Object *obj)
5847 {
5848    printf("!!! NOW FIXING \n");
5849    return EINA_FALSE;
5850 }
5851
5852 EAPI void
5853 elm_genlist_pinch_zoom_set(Evas_Object *obj, Eina_Bool emode)
5854 {
5855    printf("!!! NOW FIXING \n");
5856 }
5857
5858
5859 ////////////////////////////////////////////////////////////////////////
5860 //  EDIT  MODE
5861 ////////////////////////////////////////////////////////////////////////
5862
5863 static void
5864 _effect_item_controls(Elm_Genlist_Item *it, int itx, int ity)
5865 {
5866    if (!it->wd->edit_mode) return;
5867    evas_object_resize(it->edit_obj,it->w, it->h);
5868    evas_object_move(it->edit_obj, itx, ity);
5869 }
5870
5871 static void
5872 _effect_item_realize(Elm_Genlist_Item *it, Eina_Bool effect_on)
5873 {
5874    if ((it->effect_item_realized) || (it->delete_me)) return;
5875    char buf[1024];
5876
5877    it->edit_obj = edje_object_add(evas_object_evas_get(it->base.widget));
5878    edje_object_scale_set(it->edit_obj, elm_widget_scale_get(it->base.widget) *
5879                          _elm_config->scale);
5880    evas_object_smart_member_add(it->edit_obj, it->wd->pan_smart);
5881    elm_widget_sub_object_add(it->base.widget, it->edit_obj);
5882
5883    if (it->flags & ELM_GENLIST_ITEM_SUBITEMS) strncpy(buf, "tree", sizeof(buf));
5884    else strncpy(buf, "item", sizeof(buf));
5885    if (it->wd->compress) strncat(buf, "_compress", sizeof(buf) - strlen(buf));
5886
5887    strncat(buf, "/", sizeof(buf) - strlen(buf));
5888
5889    if (it->itc->edit_item_style && strcmp(it->itc->edit_item_style, "default"))
5890      {
5891         strncat(buf, it->itc->edit_item_style, sizeof(buf) - strlen(buf));
5892         _elm_theme_object_set(it->base.widget, it->edit_obj, "genlist", buf, elm_widget_style_get(it->base.widget));
5893      }
5894    else
5895      {
5896         _elm_theme_object_set(it->base.widget, it->edit_obj, "genlist", "item/edit_default", elm_widget_style_get(it->base.widget));
5897      }
5898
5899    if (it->wd->reorder_mode)
5900      {
5901         if (effect_on) edje_object_signal_emit(it->edit_obj, "elm,state,reorder_enabled_effect", "elm");
5902         else edje_object_signal_emit(it->edit_obj, "elm,state,reorder_enabled", "elm");
5903      }
5904    if (effect_on) edje_object_signal_emit(it->edit_obj, "elm,state,emode_enabled_effect", "elm");
5905    else edje_object_signal_emit(it->edit_obj, "elm,state,emode_enabled", "elm");
5906
5907    if (it->disabled) edje_object_signal_emit(it->edit_obj, "elm,state,disabled", "elm");
5908    else edje_object_signal_emit(it->edit_obj, "elm,state,enabled", "elm");
5909
5910
5911    if ((it->wd->edit_mode))
5912      {
5913         if (it->itc->func.icon_get)
5914           {
5915              const Eina_List *l;
5916              const char *key;
5917
5918              it->icons = elm_widget_stringlist_get(edje_object_data_get(it->edit_obj, "edit_icons"));
5919              EINA_LIST_FOREACH(it->icons, l, key)
5920                {
5921                   Evas_Object *ic = it->itc->func.icon_get
5922                      (it->base.data, it->base.widget, l->data);
5923
5924                   if (ic)
5925                     {
5926                        it->edit_icon_objs = eina_list_append(it->edit_icon_objs, ic);
5927                        edje_object_part_swallow(it->edit_obj, key, ic);
5928                        evas_object_show(ic);
5929                        elm_widget_sub_object_add(it->base.widget, ic);
5930                     }
5931                }
5932           }
5933      }
5934    edje_object_part_swallow(it->edit_obj, "original_edc", it->base.view);
5935    _effect_item_controls(it,it->scrl_x, it->scrl_y);
5936    evas_object_show(it->edit_obj);
5937
5938    it->effect_item_realized = EINA_TRUE;
5939    it->want_unrealize = EINA_FALSE;
5940 }
5941
5942 static void
5943 _effect_item_unrealize(Elm_Genlist_Item *it)
5944 {
5945    Evas_Object *icon;
5946
5947    if (!it->effect_item_realized) return;
5948    if (it->wd->reorder_it && it->wd->reorder_it == it) return;
5949
5950    edje_object_signal_emit(it->edit_obj, "elm,state,reorder_disable_effect", "elm");
5951    edje_object_signal_emit(it->edit_obj, "elm,state,sel,disable", "elm");
5952    edje_object_message_signal_process(it->edit_obj);
5953    edje_object_part_unswallow(it->edit_obj, it->base.view);
5954    evas_object_smart_member_add(it->base.view, it->wd->pan_smart);
5955    elm_widget_sub_object_add(it->base.widget, it->base.view);
5956    //   evas_object_smart_callback_call(it->edit_obj, "unrealized", it);
5957    //   _item_cache_add(it);
5958    evas_object_del(it->edit_obj);
5959    it->edit_obj = NULL;
5960    EINA_LIST_FREE(it->edit_icon_objs, icon)
5961       evas_object_del(icon);
5962
5963 //   edje_object_signal_emit(it->edit_obj, "elm,state,edit_end,disable", "elm");
5964    it->effect_item_realized = EINA_FALSE;
5965 }
5966
5967 /**
5968  * Get Genlist edit mode
5969  *
5970  * @param obj The genlist object
5971  * @return The edit mode status
5972  * (EINA_TRUE = edit mode, EINA_FALSE = normal mode
5973  *
5974  * @ingroup Genlist
5975  */
5976 EAPI Eina_Bool
5977 elm_genlist_edit_mode_get(const Evas_Object *obj)
5978 {
5979    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
5980    Widget_Data *wd = elm_widget_data_get(obj);
5981    if (!wd) return EINA_FALSE;
5982
5983    if (wd->edit_mode) return EINA_TRUE;
5984    else return EINA_FALSE;
5985 }
5986
5987 /**
5988  * Set Genlist edit mode
5989  *
5990  * This sets Genlist edit mode.
5991  *
5992  * @param obj The Genlist object
5993  * @param emode ELM_GENLIST_EDIT_MODE_{NONE & REORDER & INSERT & DELETE & SELECT & SELECT_ALL}
5994  * @param edit_class Genlist edit class (Elm_Genlist_Edit_Class structure)
5995  *
5996  * @ingroup Genlist
5997  */
5998 EAPI void
5999 elm_genlist_edit_mode_set(Evas_Object *obj, Eina_Bool edit_mode)
6000 {
6001    ELM_CHECK_WIDTYPE(obj, widtype);
6002
6003    Item_Block *itb;
6004    Eina_List *l;
6005    Elm_Genlist_Item *it;
6006
6007    Widget_Data *wd = elm_widget_data_get(obj);
6008    if (!wd) return;
6009    if (wd->edit_mode == edit_mode) return;
6010
6011    wd->edit_mode = edit_mode;
6012    if (!wd->edit_mode)
6013      {
6014         EINA_INLIST_FOREACH(wd->blocks, itb)
6015           {
6016              if (itb->realized)
6017                {
6018                   EINA_LIST_FOREACH(itb->items, l, it)
6019                     {
6020                        if (it->flags != ELM_GENLIST_ITEM_GROUP && it->realized)
6021                          {
6022                             _effect_item_unrealize(it);
6023                          }
6024                     }
6025                }
6026           }
6027         _item_cache_zero(wd);
6028      }
6029    else
6030      {
6031
6032         EINA_INLIST_FOREACH(wd->blocks, itb)
6033           {
6034              if (itb->realized)
6035                {
6036                   EINA_LIST_FOREACH(itb->items, l, it)
6037                     {
6038                        if (it->flags != ELM_GENLIST_ITEM_GROUP && it->realized)
6039                          {
6040                             if(it->selected) _item_unselect(it);
6041                             if (it->itc->edit_item_style) _effect_item_realize(it, EINA_TRUE);
6042                          }
6043                     }
6044                 }
6045            }
6046       }
6047
6048    if (wd->calc_job) ecore_job_del(wd->calc_job);
6049    wd->calc_job = ecore_job_add(_calc_job, wd);
6050 }
6051
6052 /**
6053  * Delete selected items in genlist edit mode.
6054  *
6055  * @param obj The genlist object
6056  *
6057  * @ingroup Genlist
6058  */
6059 EAPI void
6060 elm_genlist_edit_selected_items_del(Evas_Object *obj)
6061 {
6062    fprintf(stderr, "=================> Caution!!! <========================\n");
6063    fprintf(stderr, "==> elm_genlist_edit_selected_items_del() is deprecated. <=======\n");
6064    fprintf(stderr, "=======================================================\n");
6065 }
6066
6067 EAPI void
6068 elm_genlist_selected_items_del(Evas_Object *obj)
6069 {
6070    fprintf(stderr, "=================> Caution!!! <========================\n");
6071    fprintf(stderr, "==> elm_genlist_selected_items_del() is deprecated. <=======\n");
6072    fprintf(stderr, "==> Please use elm_genlist_edit_selected_items_del() instead. <==\n");
6073    fprintf(stderr, "=======================================================\n");
6074 }
6075
6076 /**
6077  * Get a list of selected items in genlist
6078  *
6079  * This returns a list of the selected items in the genlist. The list
6080  * contains Elm_Genlist_Item pointers. The list must be freed by the
6081  * caller when done with eina_list_free(). The item pointers in the list
6082  * are only vallid so long as those items are not deleted or the genlist is
6083  * not deleted.
6084  *
6085  * @param obj The genlist object
6086  * @return The list of selected items, nor NULL if none are selected.
6087  *
6088  * @ingroup Genlist
6089  */
6090 EAPI Eina_List *
6091 elm_genlist_edit_selected_items_get(const Evas_Object *obj)
6092 {
6093    fprintf(stderr, "========================> Caution!!! <==========================\n");
6094    fprintf(stderr, "==> elm_genlist_edit_selected_items_get() is deprecated. <=======\n");
6095    fprintf(stderr, "================================================================\n");
6096    return NULL;
6097 }
6098
6099 // TODO : add comment
6100 EAPI void
6101 elm_genlist_edit_item_selected_set(Elm_Genlist_Item *it,
6102                                    Eina_Bool         selected)
6103 {
6104    fprintf(stderr, "========================> Caution!!! <==========================\n");
6105    fprintf(stderr, "==> elm_genlist_edit_item_selected_set() is deprecated. <=======\n");
6106    fprintf(stderr, "================================================================\n");
6107 }
6108
6109 // TODO : add comment
6110 EAPI Eina_Bool
6111 elm_genlist_edit_item_selected_get(const Elm_Genlist_Item *it)
6112 {
6113    fprintf(stderr, "========================> Caution!!! <==========================\n");
6114    fprintf(stderr, "==> elm_genlist_edit_item_selected_get() is deprecated. <=======\n");
6115    fprintf(stderr, "================================================================\n");
6116    return EINA_FALSE;
6117 }
6118
6119 /**
6120  * Set a given item's rename mode
6121  *
6122  * This renames the item's label from genlist
6123  *
6124  * @param it The item
6125  * @param renamed set if emode is EINA_TRUE, unset if emode is EINA_FALSE
6126  *
6127  * @ingroup Genlist
6128  */
6129 EAPI void
6130 elm_genlist_item_rename_mode_set(Elm_Genlist_Item *it, Eina_Bool renamed)
6131           {
6132    if (!it) return;
6133
6134    if (renamed)
6135                     {
6136         _item_unrealize(it);
6137         it->renamed = EINA_TRUE;
6138         it->wd->rename_it = it;
6139         it->nocache = EINA_TRUE;
6140                        if (it->selected)  _item_unselect(it);
6141
6142         if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
6143         it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
6144           }
6145         else
6146           {
6147         if (it->renamed)
6148                               {
6149              it->renamed = EINA_FALSE;
6150              it->nocache = EINA_TRUE;
6151              it->wd->rename_it = NULL;
6152              _item_cache_zero(it->wd);
6153              elm_genlist_item_update(it);
6154                }
6155           }
6156      }
6157
6158 EAPI Eina_Bool
6159 elm_genlist_item_rename_mode_get(Elm_Genlist_Item *item)
6160 {
6161    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, EINA_FALSE);
6162    return item->renamed;
6163 }
6164
6165 static void _sweep_finish(void *data, Evas_Object *o, const char *emission, const char *source)
6166 {
6167    Elm_Genlist_Item *it = data;
6168
6169    _delete_sweep_objs(it);
6170 }
6171
6172 static Eina_Bool
6173 _scr_hold_timer_cb(void *data)
6174 {
6175    Elm_Genlist_Item *it = data;
6176    elm_smart_scroller_hold_set(it->wd->scr, EINA_FALSE);
6177    it->wd->scr_hold_timer = NULL;
6178    return ECORE_CALLBACK_CANCEL;
6179 }
6180
6181 static void
6182 _delete_sweep_objs(Elm_Genlist_Item *it)
6183 {
6184    Evas_Object *ic;
6185
6186    elm_widget_stringlist_free(it->sweep_labels);
6187    it->sweep_labels = NULL;
6188    elm_widget_stringlist_free(it->sweep_icons);
6189    it->sweep_icons = NULL;
6190    EINA_LIST_FREE(it->sweep_icon_objs, ic)
6191       evas_object_del(ic);
6192 }
6193
6194 static void
6195 _create_sweep_objs(Elm_Genlist_Item *it)
6196 {
6197    Evas_Object *ic;
6198    const Eina_List *l;
6199    const char *key;
6200
6201    if (it->itc->func.label_get)
6202      {
6203         it->sweep_labels =
6204            elm_widget_stringlist_get(edje_object_data_get(it->base.view,
6205                                                           "sweep_labels"));
6206         EINA_LIST_FOREACH(it->sweep_labels, l, key)
6207           {
6208              char *s = it->itc->func.label_get
6209                 ((void *)it->base.data, it->base.widget, l->data);
6210
6211              if (s)
6212                {
6213                   edje_object_part_text_set(it->base.view, l->data, s);
6214                   free(s);
6215                }
6216           }
6217      }
6218    if (it->itc->func.icon_get)
6219      {
6220         it->sweep_icons =
6221            elm_widget_stringlist_get(edje_object_data_get(it->base.view,
6222                                                           "sweep_icons"));
6223         EINA_LIST_FOREACH(it->sweep_icons, l, key)
6224           {
6225              ic = it->itc->func.icon_get
6226                 ((void *)it->base.data, it->base.widget, l->data);
6227
6228              if (ic)
6229                {
6230                   it->sweep_icon_objs = eina_list_append(it->sweep_icon_objs, ic);
6231                   edje_object_part_swallow(it->base.view, key, ic);
6232                   evas_object_show(ic);
6233                   elm_widget_sub_object_add(it->base.widget, ic);
6234                }
6235           }
6236      }
6237 }
6238
6239 static void
6240 _item_slide(Elm_Genlist_Item *it, Eina_Bool slide_to_right)
6241 {
6242    const Eina_List *l;
6243    Elm_Genlist_Item *it2;
6244    const char *allow_slide;
6245
6246    allow_slide = edje_object_data_get(it->base.view, "allow_slide");
6247    if ((!allow_slide) || (atoi(allow_slide) != 1))
6248       return;
6249
6250    if (slide_to_right)
6251      {
6252         if (it->sweeped) return;
6253         if (it->wd->scr_hold_timer)
6254           {
6255              ecore_timer_del(it->wd->scr_hold_timer);
6256              it->wd->scr_hold_timer = NULL;
6257           }
6258         elm_smart_scroller_hold_set(it->wd->scr, EINA_TRUE);
6259         it->wd->scr_hold_timer = ecore_timer_add(0.1, _scr_hold_timer_cb, it);
6260
6261         _delete_sweep_objs(it);
6262         _create_sweep_objs(it);
6263         edje_object_signal_emit(it->base.view, "elm,state,slide,right", "elm");
6264         it->wd->sweeped_items = eina_list_append(it->wd->sweeped_items, it);
6265         it->wassweeped = EINA_TRUE;
6266         it->sweeped = EINA_TRUE;
6267
6268         EINA_LIST_FOREACH(it->wd->sweeped_items, l, it2)
6269           {
6270              if (it2 != it)
6271                {
6272                   it2->sweeped = EINA_FALSE;
6273                   edje_object_signal_emit(it2->base.view, "elm,state,slide,left", "elm");
6274                   edje_object_signal_callback_add(it2->base.view, "elm,action,sweep,left,finish", "elm", _sweep_finish, it2);
6275                   it2->wd->sweeped_items = eina_list_remove(it2->wd->sweeped_items, it2);
6276                }
6277           }
6278      }
6279    else
6280      {
6281         if (!it->sweeped) return;
6282         edje_object_signal_emit(it->base.view, "elm,state,slide,left", "elm");
6283         edje_object_signal_callback_add(it->base.view, "elm,action,sweep,left,finish", "elm", _sweep_finish, it);
6284         it->wd->sweeped_items = eina_list_remove(it->wd->sweeped_items, it);
6285         it->sweeped = EINA_FALSE;
6286      }
6287 }
6288
6289 static void
6290 _item_auto_scroll(void *data)
6291 {
6292    Widget_Data *wd = data;
6293    if (!wd) return;
6294
6295    if ((wd->expand_item) && (!wd->auto_scrolled))
6296      {
6297         Elm_Genlist_Item  *it;
6298         Eina_List *l;
6299         Evas_Coord ox, oy, ow, oh;
6300         evas_object_geometry_get(wd->obj, &ox, &oy, &ow, &oh);
6301
6302         wd->auto_scrolled = EINA_TRUE;
6303         if (wd->expand_item->scrl_y > (oh + oy) / 2)
6304           {
6305             EINA_LIST_FOREACH(wd->expand_item->items, l, it)
6306               {
6307                  elm_genlist_item_bring_in(it);
6308               }
6309           }
6310      }
6311 }