================================================================
[framework/uifw/elementary.git] / src / lib / elm_gengrid.c
1 #include <Elementary.h>
2 #include <Elementary_Cursor.h>
3 #include "elm_priv.h"
4
5 /**
6  * @defgroup Gengrid Gengrid
7  *
8  * This widget aims to position objects in a grid layout while
9  * actually building only the visible ones, using the same idea as
10  * genlist: the user define a class for each item, specifying
11  * functions that will be called at object creation and deletion.
12  *
13  * Signals that you can add callbacks for are:
14  *
15  * clicked - The user has double-clicked a item. The event_info
16  * parameter is the Gengrid item that was double-clicked.
17  *
18  * selected - The user has made an item selected. The event_info
19  * parameter is the Gengrid item that was selected.
20  *
21  * unselected - The user has made an item unselected. The event_info
22  * parameter is the Gengrid item that was unselected.
23  *
24  * realized - This is called when the item in the Gengrid is created
25  * as a real evas object. event_info is the Gengrid item that was
26  * created. The object may be deleted at any time, so it is up to the
27  * caller to not use the object pointer from
28  * elm_gengrid_item_object_get() in a way where it may point to freed
29  * objects.
30  *
31  * unrealized - This is called when the real evas object for this item
32  * is deleted. event_info is the Gengrid item that was created.
33  *
34  * changed - Called when an item is added, removed, resized or moved
35  * and when gengrid is resized or horizontal property changes.
36  *
37  * drag,start,up - Called when the item in the Gengrid has been
38  * dragged (not scrolled) up.
39  *
40  * drag,start,down - Called when the item in the Gengrid has been
41  * dragged (not scrolled) down.
42  *
43  * drag,start,left - Called when the item in the Gengrid has been
44  * dragged (not scrolled) left.
45  *
46  * drag,start,right - Called when the item in the Gengrid has been
47  * dragged (not scrolled) right.
48  *
49  * drag,stop - Called when the item in the Gengrid has stopped being
50  * dragged.
51  *
52  * drag - Called when the item in the Gengrid is being dragged.
53  *
54  * scroll - called when the content has been scrolled (moved).
55  *
56  * scroll,drag,start - called when dragging the content has started.
57  *
58  * scroll,drag,stop - called when dragging the content has stopped.
59  *
60  *
61  * A item in the Gengrid can have 0 or more text labels (they can be
62  * regular text or textblock - that's up to the style to determine), 0
63  * or more icons (which are simply objects swallowed into the Gengrid
64  * item) and 0 or more boolean states that can be used for check,
65  * radio or other indicators by the edje theme style.  A item may be
66  * one of several styles (Elementary provides 1 by default -
67  * "default", but this can be extended by system or application custom
68  * themes/overlays/extensions).
69  *
70  * In order to implement the ability to add and delete items on the
71  * fly, Gengrid implements a class/callback system where the
72  * application provides a structure with information about that type
73  * of item (Gengrid may contain multiple different items with
74  * different classes, states and styles). Gengrid will call the
75  * functions in this struct (methods) when a item is "realized" (that
76  * is created dynamically while scrolling). All objects will simply be
77  * deleted when no longer needed with evas_object_del(). The
78  * Elm_GenGrid_Item_Class structure contains the following members:
79  *
80  * item_style - This is a constant string and simply defines the name
81  * of the item style. It must be specified and the default should be
82  * "default".
83  *
84  * func.label_get - This function is called when an actual item object
85  * is created. The data parameter is the one passed to
86  * elm_gengrid_item_append() and related item creation functions. The
87  * obj parameter is the Gengrid object and the part parameter is the
88  * string name of the text part in the edje design that is listed as
89  * one of the possible labels that can be set. This function must
90  * return a strdup'()ed string as the caller will free() it when done.
91  *
92  * func.icon_get - This function is called when an actual item object
93  * is created. The data parameter is the one passed to
94  * elm_gengrid_item_append() and related item creation functions. The
95  * obj parameter is the Gengrid object and the part parameter is the
96  * string name of the icon part in the edje design that is listed as
97  * one of the possible icons that can be set. This must return NULL
98  * for no object or a valid object. The object will be deleted by
99  * Gengrid on shutdown or when the item is unrealized.
100  *
101  * func.state_get - This function is called when an actual item object
102  * is created. The data parameter is the one passed to
103  * elm_gengrid_item_append() and related item creation functions. The
104  * obj parameter is the Gengrid object and the part parameter is the
105  * string name of th state part in the edje design that is listed as
106  * one of the possible states that can be set. Return 0 for false and
107  * 1 for true. Gengrid will emit a signal to the edje object with
108  * "elm,state,XXX,active" "elm" when true (the default is false),
109  * where XXX is the name of the part.
110  *
111  * func.del - This is called when elm_gengrid_item_del() is called on
112  * a item or elm_gengrid_clear() is called on the Gengrid. This is
113  * intended for use when actual Gengrid items are deleted, so any
114  * backing data attached to the item (e.g. its data parameter on
115  * creation) can be deleted.
116  *
117  * If the application wants multiple items to be able to be selected,
118  * elm_gengrid_multi_select_set() can enable this. If the Gengrid is
119  * single-selection only (the default), then
120  * elm_gengrid_select_item_get() will return the selected item, if
121  * any, or NULL if none is selected. If the Gengrid is multi-select
122  * then elm_gengrid_selected_items_get() will return a list (that is
123  * only valid as long as no items are modified (added, deleted,
124  * selected or unselected).
125  *
126  * If a item changes (state of boolean changes, label or icons
127  * change), then use elm_gengrid_item_update() to have Gengrid update
128  * the item with the new state. Gengrid will re-realize the item thus
129  * call the functions in the _Elm_Gengrid_Item_Class for that item.
130  *
131  * To programmatically (un)select a item use
132  * elm_gengrid_item_selected_set().  To get its selected state use
133  * elm_gengrid_item_selected_get(). To make a item disabled (unable to
134  * be selected and appear differently) use
135  * elm_gengrid_item_disabled_set() to set this and
136  * elm_gengrid_item_disabled_get() to get the disabled state.
137  *
138  * Cells will only call their selection func and callback when first
139  * becoming selected. Any further clicks will do nothing, unless you
140  * enable always select with
141  * elm_gengrid_always_select_mode_set(). This means event if selected,
142  * every click will make the selected callbacks be called.
143  * elm_gengrid_no_select_mode_set() will turn off the ability to
144  * select items entirely and they will neither appear selected nor
145  * call selected callback function.
146  *
147  * Remember that you can create new styles and add your own theme
148  * augmentation per application with elm_theme_extension_add(). If you
149  * absolutely must have a specific style that overrides any theme the
150  * user or system sets up you can use elm_theme_overlay_add() to add
151  * such a file.
152  *
153  * --
154  * TODO:
155  *  * Handle non-homogeneous objects too.
156  */
157
158 typedef struct _Widget_Data Widget_Data;
159 typedef struct _Pan         Pan;
160
161 #define PRELOAD 1
162
163 struct _Elm_Gengrid_Item
164 {
165    Elm_Widget_Item               base;
166    EINA_INLIST;
167    Evas_Object                  *spacer;
168    const Elm_Gengrid_Item_Class *gic;
169    Ecore_Timer                  *long_timer;
170    Widget_Data                  *wd;
171    Eina_List                    *labels, *icons, *states, *icon_objs;
172    struct
173    {
174       Evas_Smart_Cb func;
175       const void   *data;
176    } func;
177
178    Evas_Coord x, y, dx, dy;
179    int        relcount;
180    int        walking;
181
182    struct
183    {
184       const void                 *data;
185       Elm_Tooltip_Item_Content_Cb content_cb;
186       Evas_Smart_Cb               del_cb;
187       const char                 *style;
188    } tooltip;
189
190    const char *mouse_cursor;
191
192    Eina_Bool   want_unrealize : 1;
193    Eina_Bool   realized : 1;
194    Eina_Bool   dragging : 1;
195    Eina_Bool   down : 1;
196    Eina_Bool   delete_me : 1;
197    Eina_Bool   display_only : 1;
198    Eina_Bool   disabled : 1;
199    Eina_Bool   selected : 1;
200    Eina_Bool   hilighted : 1;
201 };
202
203 struct _Widget_Data
204 {
205    Evas_Object      *self, *scr;
206    Evas_Object      *pan_smart;
207    Pan              *pan;
208    Eina_Inlist      *items;
209    Ecore_Job        *calc_job;
210    Eina_List        *selected;
211    Elm_Gengrid_Item *last_selected_item;
212    double            align_x, align_y;
213
214    Evas_Coord        pan_x, pan_y;
215    Evas_Coord        item_width, item_height; /* Each item size */
216    Evas_Coord        minw, minh; /* Total obj size */
217    unsigned int      nmax;
218    long              count;
219    int               walking;
220
221    Eina_Bool         horizontal : 1;
222    Eina_Bool         on_hold : 1;
223    Eina_Bool         longpressed : 1;
224    Eina_Bool         multi : 1;
225    Eina_Bool         no_select : 1;
226    Eina_Bool         wasselected : 1;
227    Eina_Bool         always_select : 1;
228    Eina_Bool         clear_me : 1;
229 };
230
231 #define ELM_GENGRID_ITEM_FROM_INLIST(item) \
232   ((item) ? EINA_INLIST_CONTAINER_GET(item, Elm_Gengrid_Item) : NULL)
233
234 struct _Pan
235 {
236    Evas_Object_Smart_Clipped_Data __clipped_data;
237    Widget_Data                   *wd;
238 };
239
240 static const char *widtype = NULL;
241 static void      _item_hilight(Elm_Gengrid_Item *item);
242 static void      _item_unrealize(Elm_Gengrid_Item *item);
243 static void      _item_select(Elm_Gengrid_Item *item);
244 static void      _item_unselect(Elm_Gengrid_Item *item);
245 static void      _calc_job(void *data);
246 static void      _on_focus_hook(void        *data,
247                                 Evas_Object *obj);
248 static Eina_Bool _item_multi_select_up(Widget_Data *wd);
249 static Eina_Bool _item_multi_select_down(Widget_Data *wd);
250 static Eina_Bool _item_multi_select_left(Widget_Data *wd);
251 static Eina_Bool _item_multi_select_right(Widget_Data *wd);
252 static Eina_Bool _item_single_select_up(Widget_Data *wd);
253 static Eina_Bool _item_single_select_down(Widget_Data *wd);
254 static Eina_Bool _item_single_select_left(Widget_Data *wd);
255 static Eina_Bool _item_single_select_right(Widget_Data *wd);
256 static Eina_Bool _event_hook(Evas_Object       *obj,
257                              Evas_Object       *src,
258                              Evas_Callback_Type type,
259                              void              *event_info);
260 static Eina_Bool _deselect_all_items(Widget_Data *wd);
261
262 static Evas_Smart_Class _pan_sc = EVAS_SMART_CLASS_INIT_VERSION;
263
264 static Eina_Bool
265 _event_hook(Evas_Object       *obj,
266             Evas_Object *src   __UNUSED__,
267             Evas_Callback_Type type,
268             void              *event_info)
269 {
270    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
271    Evas_Event_Key_Down *ev = event_info;
272    Widget_Data *wd = elm_widget_data_get(obj);
273    if (!wd) return EINA_FALSE;
274    if (!wd->items) return EINA_FALSE;
275    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
276    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
277
278    Elm_Gengrid_Item *item = NULL;
279    Evas_Coord x = 0;
280    Evas_Coord y = 0;
281    Evas_Coord step_x = 0;
282    Evas_Coord step_y = 0;
283    Evas_Coord v_w = 0;
284    Evas_Coord v_h = 0;
285    Evas_Coord page_x = 0;
286    Evas_Coord page_y = 0;
287
288    elm_smart_scroller_child_pos_get(wd->scr, &x, &y);
289    elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y);
290    elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y);
291    elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h);
292
293    if ((!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left")))
294      {
295         if ((wd->horizontal) &&
296             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
297               (_item_multi_select_up(wd)))
298              || (_item_single_select_up(wd))))
299           {
300              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
301              return EINA_TRUE;
302           }
303         else if ((!wd->horizontal) &&
304                  (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
305                    (_item_multi_select_left(wd)))
306                   || (_item_single_select_left(wd))))
307           {
308              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
309              return EINA_TRUE;
310           }
311         else
312           x -= step_x;
313      }
314    else if ((!strcmp(ev->keyname, "Right")) || (!strcmp(ev->keyname, "KP_Right")))
315      {
316         if ((wd->horizontal) &&
317             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
318               (_item_multi_select_down(wd)))
319              || (_item_single_select_down(wd))))
320           {
321              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
322              return EINA_TRUE;
323           }
324         else if ((!wd->horizontal) &&
325                  (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
326                    (_item_multi_select_right(wd)))
327                   || (_item_single_select_right(wd))))
328           {
329              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
330              return EINA_TRUE;
331           }
332         else
333           x += step_x;
334      }
335    else if ((!strcmp(ev->keyname, "Up")) || (!strcmp(ev->keyname, "KP_Up")))
336      {
337         if ((wd->horizontal) &&
338             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
339               (_item_multi_select_left(wd)))
340              || (_item_single_select_left(wd))))
341           {
342              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
343              return EINA_TRUE;
344           }
345         else if ((!wd->horizontal) &&
346                  (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
347                    (_item_multi_select_up(wd)))
348                   || (_item_single_select_up(wd))))
349           {
350              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
351              return EINA_TRUE;
352           }
353         else
354           y -= step_y;
355      }
356    else if ((!strcmp(ev->keyname, "Down")) || (!strcmp(ev->keyname, "KP_Down")))
357      {
358         if ((wd->horizontal) &&
359             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
360               (_item_multi_select_right(wd)))
361              || (_item_single_select_right(wd))))
362           {
363              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
364              return EINA_TRUE;
365           }
366         else if ((!wd->horizontal) &&
367                  (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
368                    (_item_multi_select_down(wd)))
369                   || (_item_single_select_down(wd))))
370           {
371              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
372              return EINA_TRUE;
373           }
374         else
375           y += step_y;
376      }
377    else if ((!strcmp(ev->keyname, "Home")) || (!strcmp(ev->keyname, "KP_Home")))
378      {
379         item = elm_gengrid_first_item_get(obj);
380         elm_gengrid_item_bring_in(item);
381         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
382         return EINA_TRUE;
383      }
384    else if ((!strcmp(ev->keyname, "End")) || (!strcmp(ev->keyname, "KP_End")))
385      {
386         item = elm_gengrid_last_item_get(obj);
387         elm_gengrid_item_bring_in(item);
388         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
389         return EINA_TRUE;
390      }
391    else if ((!strcmp(ev->keyname, "Prior")) ||
392             (!strcmp(ev->keyname, "KP_Prior")))
393      {
394         if (wd->horizontal)
395           {
396              if (page_x < 0)
397                x -= -(page_x * v_w) / 100;
398              else
399                x -= page_x;
400           }
401         else
402           {
403              if (page_y < 0)
404                y -= -(page_y * v_h) / 100;
405              else
406                y -= page_y;
407           }
408      }
409    else if ((!strcmp(ev->keyname, "Next")) || (!strcmp(ev->keyname, "KP_Next")))
410      {
411         if (wd->horizontal)
412           {
413              if (page_x < 0)
414                x += -(page_x * v_w) / 100;
415              else
416                x += page_x;
417           }
418         else
419           {
420              if (page_y < 0)
421                y += -(page_y * v_h) / 100;
422              else
423                y += page_y;
424           }
425      }
426    else if (!strcmp(ev->keyname, "Escape"))
427      {
428         if (!_deselect_all_items(wd)) return EINA_FALSE;
429         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
430         return EINA_TRUE;
431      }
432    else return EINA_FALSE;
433
434    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
435    elm_smart_scroller_child_pos_set(wd->scr, x, y);
436    return EINA_TRUE;
437 }
438
439 static Eina_Bool
440 _deselect_all_items(Widget_Data *wd)
441 {
442    if (!wd->selected) return EINA_FALSE;
443    while(wd->selected)
444      elm_gengrid_item_selected_set(wd->selected->data, EINA_FALSE);
445
446    return EINA_TRUE;
447 }
448
449 static Eina_Bool
450 _item_multi_select_left(Widget_Data *wd)
451 {
452    if (!wd->selected) return EINA_FALSE;
453
454    Elm_Gengrid_Item *prev = elm_gengrid_item_prev_get(wd->last_selected_item);
455    if (!prev) return EINA_TRUE;
456    if (elm_gengrid_item_selected_get(prev))
457      {
458         elm_gengrid_item_selected_set(wd->last_selected_item, EINA_FALSE);
459         wd->last_selected_item = prev;
460         elm_gengrid_item_show(wd->last_selected_item);
461      }
462    else
463      {
464         elm_gengrid_item_selected_set(prev, EINA_TRUE);
465         elm_gengrid_item_show(prev);
466      }
467
468    return EINA_TRUE;
469 }
470
471 static Eina_Bool
472 _item_multi_select_right(Widget_Data *wd)
473 {
474    if (!wd->selected) return EINA_FALSE;
475
476    Elm_Gengrid_Item *next = elm_gengrid_item_next_get(wd->last_selected_item);
477    if (!next) return EINA_TRUE;
478    if (elm_gengrid_item_selected_get(next))
479      {
480         elm_gengrid_item_selected_set(wd->last_selected_item, EINA_FALSE);
481         wd->last_selected_item = next;
482         elm_gengrid_item_show(wd->last_selected_item);
483      }
484    else
485      {
486         elm_gengrid_item_selected_set(next, EINA_TRUE);
487         elm_gengrid_item_show(next);
488      }
489
490    return EINA_TRUE;
491 }
492
493 static Eina_Bool
494 _item_multi_select_up(Widget_Data *wd)
495 {
496    unsigned int i;
497    Eina_Bool r = EINA_TRUE;
498
499    if (!wd->selected) return EINA_FALSE;
500
501    for (i = 0; (r) && (i < wd->nmax); i++)
502      r &= _item_multi_select_left(wd);
503
504    return r;
505 }
506
507 static Eina_Bool
508 _item_multi_select_down(Widget_Data *wd)
509 {
510    unsigned int i;
511    Eina_Bool r = EINA_TRUE;
512
513    if (!wd->selected) return EINA_FALSE;
514
515    for (i = 0; (r) && (i < wd->nmax); i++)
516      r &= _item_multi_select_right(wd);
517
518    return r;
519 }
520
521 static Eina_Bool
522 _item_single_select_up(Widget_Data *wd)
523 {
524    unsigned int i;
525
526    Elm_Gengrid_Item *prev;
527
528    if (!wd->selected)
529      {
530         prev = ELM_GENGRID_ITEM_FROM_INLIST(wd->items->last);
531         while ((prev) && (prev->delete_me))
532           prev = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(prev)->prev);
533         elm_gengrid_item_selected_set(prev, EINA_TRUE);
534         elm_gengrid_item_show(prev);
535         return EINA_TRUE;
536      }
537    else prev = elm_gengrid_item_prev_get(wd->last_selected_item);
538
539    if (!prev) return EINA_FALSE;
540
541    for (i = 1; i < wd->nmax; i++)
542      {
543         Elm_Gengrid_Item *tmp = elm_gengrid_item_prev_get(prev);
544         if (!tmp) return EINA_FALSE;
545         prev = tmp;
546      }
547
548    _deselect_all_items(wd);
549
550    elm_gengrid_item_selected_set(prev, EINA_TRUE);
551    elm_gengrid_item_show(prev);
552    return EINA_TRUE;
553 }
554
555 static Eina_Bool
556 _item_single_select_down(Widget_Data *wd)
557 {
558    unsigned int i;
559
560    Elm_Gengrid_Item *next;
561
562    if (!wd->selected)
563      {
564         next = ELM_GENGRID_ITEM_FROM_INLIST(wd->items);
565         while ((next) && (next->delete_me))
566           next = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(next)->next);
567         elm_gengrid_item_selected_set(next, EINA_TRUE);
568         elm_gengrid_item_show(next);
569         return EINA_TRUE;
570      }
571    else next = elm_gengrid_item_next_get(wd->last_selected_item);
572
573    if (!next) return EINA_FALSE;
574
575    for (i = 1; i < wd->nmax; i++)
576      {
577         Elm_Gengrid_Item *tmp = elm_gengrid_item_next_get(next);
578         if (!tmp) return EINA_FALSE;
579         next = tmp;
580      }
581
582    _deselect_all_items(wd);
583
584    elm_gengrid_item_selected_set(next, EINA_TRUE);
585    elm_gengrid_item_show(next);
586    return EINA_TRUE;
587 }
588
589 static Eina_Bool
590 _item_single_select_left(Widget_Data *wd)
591 {
592    Elm_Gengrid_Item *prev;
593    if (!wd->selected)
594      {
595         prev = ELM_GENGRID_ITEM_FROM_INLIST(wd->items->last);
596         while ((prev) && (prev->delete_me))
597           prev = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(prev)->prev);
598      }
599    else prev = elm_gengrid_item_prev_get(wd->last_selected_item);
600
601    if (!prev) return EINA_FALSE;
602
603    _deselect_all_items(wd);
604
605    elm_gengrid_item_selected_set(prev, EINA_TRUE);
606    elm_gengrid_item_show(prev);
607    return EINA_TRUE;
608 }
609
610 static Eina_Bool
611 _item_single_select_right(Widget_Data *wd)
612 {
613    Elm_Gengrid_Item *next;
614    if (!wd->selected)
615      {
616         next = ELM_GENGRID_ITEM_FROM_INLIST(wd->items);
617         while ((next) && (next->delete_me))
618           next = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(next)->next);
619      }
620    else next = elm_gengrid_item_next_get(wd->last_selected_item);
621
622    if (!next) return EINA_FALSE;
623
624    _deselect_all_items(wd);
625
626    elm_gengrid_item_selected_set(next, EINA_TRUE);
627    elm_gengrid_item_show(next);
628    return EINA_TRUE;
629 }
630
631 static void
632 _on_focus_hook(void *data   __UNUSED__,
633                Evas_Object *obj)
634 {
635    Widget_Data *wd = elm_widget_data_get(obj);
636    if (!wd) return;
637    if (elm_widget_focus_get(obj))
638      {
639         edje_object_signal_emit(wd->self, "elm,action,focus", "elm");
640         evas_object_focus_set(wd->self, EINA_TRUE);
641         if ((wd->selected) && (!wd->last_selected_item))
642           wd->last_selected_item = eina_list_data_get(wd->selected);
643      }
644    else
645      {
646         edje_object_signal_emit(wd->self, "elm,action,unfocus", "elm");
647         evas_object_focus_set(wd->self, EINA_FALSE);
648      }
649 }
650
651 static void
652 _theme_hook(Evas_Object *obj)
653 {
654    Widget_Data *wd = elm_widget_data_get(obj);
655    if (!wd) return;
656    elm_smart_scroller_object_theme_set(obj, wd->scr, "gengrid", "base",
657                                        elm_widget_style_get(obj));
658 }
659
660 static void
661 _del_pre_hook(Evas_Object *obj)
662 {
663    Widget_Data *wd = elm_widget_data_get(obj);
664    if (!wd) return;
665    elm_gengrid_clear(obj);
666    evas_object_del(wd->pan_smart);
667    wd->pan_smart = NULL;
668 }
669
670 static void
671 _del_hook(Evas_Object *obj)
672 {
673    Widget_Data *wd = elm_widget_data_get(obj);
674    free(wd);
675 }
676
677 static void
678 _signal_emit_hook(Evas_Object *obj,
679                   const char  *emission,
680                   const char  *source)
681 {
682    Widget_Data *wd = elm_widget_data_get(obj);
683    if (!wd) return;
684    edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
685                            emission, source);
686 }
687
688 static void
689 _mouse_move(void        *data,
690             Evas *evas   __UNUSED__,
691             Evas_Object *obj,
692             void        *event_info)
693 {
694    Elm_Gengrid_Item *item = data;
695    Evas_Event_Mouse_Move *ev = event_info;
696    Evas_Coord minw = 0, minh = 0, x, y, dx, dy, adx, ady;
697
698    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
699      {
700         if (!item->wd->on_hold)
701           {
702              item->wd->on_hold = EINA_TRUE;
703              if (!item->wd->wasselected)
704                _item_unselect(item);
705           }
706      }
707    if ((item->dragging) && (item->down))
708      {
709         if (item->long_timer)
710           {
711              ecore_timer_del(item->long_timer);
712              item->long_timer = NULL;
713           }
714         evas_object_smart_callback_call(item->wd->self, "drag", item);
715         return;
716      }
717    if ((!item->down) || (item->wd->longpressed))
718      {
719         if (item->long_timer)
720           {
721              ecore_timer_del(item->long_timer);
722              item->long_timer = NULL;
723           }
724         return;
725      }
726    if (!item->display_only)
727      elm_coords_finger_size_adjust(1, &minw, 1, &minh);
728    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
729    x = ev->cur.canvas.x - x;
730    y = ev->cur.canvas.y - y;
731    dx = x - item->dx;
732    adx = dx;
733    if (adx < 0) adx = -dx;
734    dy = y - item->dy;
735    ady = dy;
736    if (ady < 0) ady = -dy;
737    minw /= 2;
738    minh /= 2;
739    if ((adx > minw) || (ady > minh))
740      {
741         item->dragging = 1;
742         if (item->long_timer)
743           {
744              ecore_timer_del(item->long_timer);
745              item->long_timer = NULL;
746           }
747         if (!item->wd->wasselected)
748           _item_unselect(item);
749         if (dy < 0)
750           {
751              if (ady > adx)
752                evas_object_smart_callback_call(item->wd->self, "drag,start,up",
753                                                item);
754              else
755                {
756                   if (dx < 0)
757                     evas_object_smart_callback_call(item->wd->self,
758                                                     "drag,start,left", item);
759                }
760           }
761         else
762           {
763              if (ady > adx)
764                evas_object_smart_callback_call(item->wd->self,
765                                                "drag,start,down", item);
766              else
767                {
768                   if (dx < 0)
769                     evas_object_smart_callback_call(item->wd->self,
770                                                     "drag,start,left", item);
771                   else
772                     evas_object_smart_callback_call(item->wd->self,
773                                                     "drag,start,right", item);
774                }
775           }
776      }
777 }
778
779 static Eina_Bool
780 _long_press(void *data)
781 {
782    Elm_Gengrid_Item *item = data;
783
784    item->long_timer = NULL;
785    if ((item->disabled) || (item->dragging)) return ECORE_CALLBACK_CANCEL;
786    item->wd->longpressed = EINA_TRUE;
787    evas_object_smart_callback_call(item->wd->self, "longpressed", item);
788    return ECORE_CALLBACK_CANCEL;
789 }
790
791 static void
792 _mouse_down(void        *data,
793             Evas *evas   __UNUSED__,
794             Evas_Object *obj,
795             void        *event_info)
796 {
797    Elm_Gengrid_Item *item = data;
798    Evas_Event_Mouse_Down *ev = event_info;
799    Evas_Coord x, y;
800
801    if (ev->button != 1) return;
802    item->down = 1;
803    item->dragging = 0;
804    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
805    item->dx = ev->canvas.x - x;
806    item->dy = ev->canvas.y - y;
807    item->wd->longpressed = EINA_FALSE;
808    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) item->wd->on_hold = EINA_TRUE;
809    else item->wd->on_hold = EINA_FALSE;
810    item->wd->wasselected = item->selected;
811    _item_hilight(item);
812    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
813      evas_object_smart_callback_call(item->wd->self, "clicked", item);
814    if (item->long_timer) ecore_timer_del(item->long_timer);
815    if (item->realized)
816      item->long_timer = ecore_timer_add(_elm_config->longpress_timeout,
817                                         _long_press, item);
818    else
819      item->long_timer = NULL;
820 }
821
822 static void
823 _mouse_up(void            *data,
824           Evas *evas       __UNUSED__,
825           Evas_Object *obj __UNUSED__,
826           void            *event_info)
827 {
828    Elm_Gengrid_Item *item = data;
829    Evas_Event_Mouse_Up *ev = event_info;
830    Eina_Bool dragged = EINA_FALSE;
831
832    if (ev->button != 1) return;
833    item->down = EINA_FALSE;
834    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) item->wd->on_hold = EINA_TRUE;
835    else item->wd->on_hold = EINA_FALSE;
836    if (item->long_timer)
837      {
838         ecore_timer_del(item->long_timer);
839         item->long_timer = NULL;
840      }
841    if (item->dragging)
842      {
843         item->dragging = EINA_FALSE;
844         evas_object_smart_callback_call(item->wd->self, "drag,stop", item);
845         dragged = EINA_TRUE;
846      }
847    if (item->wd->on_hold)
848      {
849         item->wd->longpressed = EINA_FALSE;
850         item->wd->on_hold = EINA_FALSE;
851         return;
852      }
853    if (item->wd->longpressed)
854      {
855         item->wd->longpressed = EINA_FALSE;
856         if (!item->wd->wasselected) _item_unselect(item);
857         item->wd->wasselected = EINA_FALSE;
858         return;
859      }
860    if (dragged)
861      {
862         if (item->want_unrealize) _item_unrealize(item);
863      }
864    if ((item->disabled) || (dragged)) return;
865    if (item->wd->multi)
866      {
867         if (!item->selected)
868           {
869              _item_hilight(item);
870              _item_select(item);
871           }
872         else _item_unselect(item);
873      }
874    else
875      {
876         if (!item->selected)
877           {
878              while (item->wd->selected)
879                _item_unselect(item->wd->selected->data);
880           }
881         else
882           {
883              const Eina_List *l, *l_next;
884              Elm_Gengrid_Item *item2;
885
886              EINA_LIST_FOREACH_SAFE(item->wd->selected, l, l_next, item2)
887                if (item2 != item) _item_unselect(item2);
888           }
889         _item_hilight(item);
890         _item_select(item);
891      }
892 }
893
894 static void
895 _item_hilight(Elm_Gengrid_Item *item)
896 {
897    if ((item->wd->no_select) || (item->delete_me) || (item->hilighted)) return;
898    edje_object_signal_emit(item->base.view, "elm,state,selected", "elm");
899    item->hilighted = EINA_TRUE;
900 }
901
902 static void
903 _item_realize(Elm_Gengrid_Item *item)
904 {
905    char buf[1024];
906    char style[1024];
907
908    if ((item->realized) || (item->delete_me)) return;
909    item->base.view = edje_object_add(evas_object_evas_get(item->wd->self));
910    edje_object_scale_set(item->base.view, elm_widget_scale_get(item->wd->self) *
911                          _elm_config->scale);
912    evas_object_smart_member_add(item->base.view, item->wd->pan_smart);
913    elm_widget_sub_object_add(item->wd->self, item->base.view);
914    snprintf(style, sizeof(style), "item/%s",
915             item->gic->item_style ? item->gic->item_style : "default");
916    _elm_theme_object_set(item->wd->self, item->base.view, "gengrid", style,
917                          elm_widget_style_get(item->wd->self));
918    item->spacer =
919        evas_object_rectangle_add(evas_object_evas_get(item->wd->self));
920    evas_object_color_set(item->spacer, 0, 0, 0, 0);
921    elm_widget_sub_object_add(item->wd->self, item->spacer);
922    evas_object_size_hint_min_set(item->spacer, 2 * _elm_config->scale, 1);
923    edje_object_part_swallow(item->base.view, "elm.swallow.pad", item->spacer);
924
925    if (item->gic->func.label_get)
926      {
927         const Eina_List *l;
928         const char *key;
929
930         item->labels =
931             elm_widget_stringlist_get(edje_object_data_get(item->base.view,
932                                                            "labels"));
933         EINA_LIST_FOREACH(item->labels, l, key)
934           {
935              char *s = item->gic->func.label_get
936                  ((void *)item->base.data, item->wd->self, l->data);
937              if (s)
938                {
939                   edje_object_part_text_set(item->base.view, l->data, s);
940                   free(s);
941                }
942           }
943      }
944
945    if (item->gic->func.icon_get)
946      {
947         const Eina_List *l;
948         const char *key;
949
950         item->icons =
951             elm_widget_stringlist_get(edje_object_data_get(item->base.view,
952                                                            "icons"));
953         EINA_LIST_FOREACH(item->icons, l, key)
954           {
955              Evas_Object *ic = item->gic->func.icon_get
956                  ((void *)item->base.data, item->wd->self, l->data);
957              if (ic)
958                {
959                   item->icon_objs = eina_list_append(item->icon_objs, ic);
960                   edje_object_part_swallow(item->base.view, key, ic);
961                   evas_object_show(ic);
962                   elm_widget_sub_object_add(item->wd->self, ic);
963                }
964           }
965      }
966
967    if (item->gic->func.state_get)
968      {
969         const Eina_List *l;
970         const char *key;
971
972         item->states =
973             elm_widget_stringlist_get(edje_object_data_get(item->base.view,
974                                                            "states"));
975         EINA_LIST_FOREACH(item->states, l, key)
976           {
977              Eina_Bool on = item->gic->func.state_get
978                  ((void *)item->base.data, item->wd->self, l->data);
979              if (on)
980                {
981                   snprintf(buf, sizeof(buf), "elm,state,%s,active", key);
982                   edje_object_signal_emit(item->base.view, buf, "elm");
983                }
984           }
985      }
986
987    if ((!item->wd->item_width) && (!item->wd->item_height))
988      {
989         edje_object_size_min_restricted_calc(item->base.view,
990                                              &item->wd->item_width,
991                                              &item->wd->item_height,
992                                              item->wd->item_width,
993                                              item->wd->item_height);
994         elm_coords_finger_size_adjust(1, &item->wd->item_width,
995                                       1, &item->wd->item_height);
996      }
997
998    evas_object_event_callback_add(item->base.view, EVAS_CALLBACK_MOUSE_DOWN,
999                                   _mouse_down, item);
1000    evas_object_event_callback_add(item->base.view, EVAS_CALLBACK_MOUSE_UP,
1001                                   _mouse_up, item);
1002    evas_object_event_callback_add(item->base.view, EVAS_CALLBACK_MOUSE_MOVE,
1003                                   _mouse_move, item);
1004
1005    if (item->selected)
1006      edje_object_signal_emit(item->base.view, "elm,state,selected", "elm");
1007    if (item->disabled)
1008      edje_object_signal_emit(item->base.view, "elm,state,disabled", "elm");
1009
1010    evas_object_show(item->base.view);
1011
1012    if (item->tooltip.content_cb)
1013      {
1014         elm_widget_item_tooltip_content_cb_set(item,
1015                                                item->tooltip.content_cb,
1016                                                item->tooltip.data, NULL);
1017         elm_widget_item_tooltip_style_set(item, item->tooltip.style);
1018      }
1019
1020    if (item->mouse_cursor)
1021      elm_widget_item_cursor_set(item, item->mouse_cursor);
1022
1023    item->realized = EINA_TRUE;
1024    item->want_unrealize = EINA_FALSE;
1025 }
1026
1027 static void
1028 _item_unrealize(Elm_Gengrid_Item *item)
1029 {
1030    Evas_Object *icon;
1031
1032    if (!item->realized) return;
1033    if (item->long_timer)
1034      {
1035         ecore_timer_del(item->long_timer);
1036         item->long_timer = NULL;
1037      }
1038    evas_object_del(item->base.view);
1039    item->base.view = NULL;
1040    evas_object_del(item->spacer);
1041    item->spacer = NULL;
1042    elm_widget_stringlist_free(item->labels);
1043    item->labels = NULL;
1044    elm_widget_stringlist_free(item->icons);
1045    item->icons = NULL;
1046    elm_widget_stringlist_free(item->states);
1047    item->states = NULL;
1048
1049    EINA_LIST_FREE(item->icon_objs, icon)
1050      evas_object_del(icon);
1051
1052    item->realized = EINA_FALSE;
1053    item->want_unrealize = EINA_FALSE;
1054 }
1055
1056 static void
1057 _item_place(Elm_Gengrid_Item *item,
1058             Evas_Coord        cx,
1059             Evas_Coord        cy)
1060 {
1061    Evas_Coord x, y, ox, oy, cvx, cvy, cvw, cvh;
1062    Evas_Coord tch, tcw, alignw = 0, alignh = 0, vw, vh;
1063
1064    item->x = cx;
1065    item->y = cy;
1066    evas_object_geometry_get(item->wd->pan_smart, &ox, &oy, &vw, &vh);
1067
1068    /* Preload rows/columns at each side of the Gengrid */
1069    cvx = ox - PRELOAD * item->wd->item_width;
1070    cvy = oy - PRELOAD * item->wd->item_height;
1071    cvw = vw + 2 * PRELOAD * item->wd->item_width;
1072    cvh = vh + 2 * PRELOAD * item->wd->item_height;
1073
1074    alignh = 0;
1075    alignw = 0;
1076
1077    if (item->wd->horizontal)
1078      {
1079         int columns, items_visible = 0, items_row;
1080
1081         if (item->wd->item_height > 0)
1082           items_visible = vh / item->wd->item_height;
1083         if (items_visible < 1)
1084           items_visible = 1;
1085
1086         columns = item->wd->count / items_visible;
1087         if (item->wd->count % items_visible)
1088           columns++;
1089
1090         tcw = item->wd->item_width * columns;
1091         alignw = (vw - tcw) * item->wd->align_x;
1092
1093         items_row = items_visible;
1094         if (items_row > item->wd->count)
1095           items_row = item->wd->count;
1096         tch = items_row * item->wd->item_height;
1097         alignh = (vh - tch) * item->wd->align_y;
1098      }
1099    else
1100      {
1101         int rows, items_visible = 0, items_col;
1102
1103         if (item->wd->item_width > 0)
1104           items_visible = vw / item->wd->item_width;
1105         if (items_visible < 1)
1106           items_visible = 1;
1107
1108         rows = item->wd->count / items_visible;
1109         if (item->wd->count % items_visible)
1110           rows++;
1111
1112         tch = item->wd->item_height * rows;
1113         alignh = (vh - tch) * item->wd->align_y;
1114
1115         items_col = items_visible;
1116         if (items_col > item->wd->count)
1117           items_col = item->wd->count;
1118         tcw = items_col * item->wd->item_width;
1119         alignw = (vw - tcw) * item->wd->align_x;
1120      }
1121
1122    x = cx * item->wd->item_width - item->wd->pan_x + ox + alignw;
1123    y = cy * item->wd->item_height - item->wd->pan_y + oy + alignh;
1124
1125    Eina_Bool was_realized = item->realized;
1126    if (ELM_RECTS_INTERSECT(x, y, item->wd->item_width, item->wd->item_height,
1127                            cvx, cvy, cvw, cvh))
1128      {
1129         _item_realize(item);
1130         if (!was_realized)
1131           evas_object_smart_callback_call(item->wd->self, "realized", item);
1132         evas_object_move(item->base.view, x, y);
1133         evas_object_resize(item->base.view, item->wd->item_width,
1134                            item->wd->item_height);
1135      }
1136    else
1137      {
1138         _item_unrealize(item);
1139         if (was_realized)
1140           evas_object_smart_callback_call(item->wd->self, "unrealized", item);
1141      }
1142 }
1143
1144 static Elm_Gengrid_Item *
1145 _item_create(Widget_Data                  *wd,
1146              const Elm_Gengrid_Item_Class *gic,
1147              const void                   *data,
1148              Evas_Smart_Cb                 func,
1149              const void                   *func_data)
1150 {
1151    Elm_Gengrid_Item *item;
1152
1153    item = elm_widget_item_new(wd->self, Elm_Gengrid_Item);
1154    if (!item) return NULL;
1155    wd->count++;
1156    item->wd = wd;
1157    item->gic = gic;
1158    item->base.data = data;
1159    item->func.func = func;
1160    item->func.data = func_data;
1161    item->mouse_cursor = NULL;
1162    return item;
1163 }
1164
1165 static void
1166 _item_del(Elm_Gengrid_Item *item)
1167 {
1168    elm_widget_item_pre_notify_del(item);
1169    if (item->selected)
1170      item->wd->selected = eina_list_remove(item->wd->selected, item);
1171    if (item->realized) _item_unrealize(item);
1172    if ((!item->delete_me) && (item->gic->func.del))
1173      item->gic->func.del((void *)item->base.data, item->wd->self);
1174    item->delete_me = EINA_TRUE;
1175    item->wd->items = eina_inlist_remove(item->wd->items, EINA_INLIST_GET(item));
1176    if (item->long_timer) ecore_timer_del(item->long_timer);
1177    if (item->tooltip.del_cb)
1178      item->tooltip.del_cb((void *)item->tooltip.data, item->base.widget, item);
1179    item->wd->walking -= item->walking;
1180    item->wd->count--;
1181    if (item->wd->calc_job) ecore_job_del(item->wd->calc_job);
1182    item->wd->calc_job = ecore_job_add(_calc_job, item->wd);
1183    elm_widget_item_del(item);
1184 }
1185
1186 static void
1187 _item_select(Elm_Gengrid_Item *item)
1188 {
1189    if ((item->wd->no_select) || (item->delete_me)) return;
1190    if (item->selected)
1191      {
1192         if (item->wd->always_select) goto call;
1193         return;
1194      }
1195    item->selected = EINA_TRUE;
1196    item->wd->selected = eina_list_append(item->wd->selected, item);
1197 call:
1198    item->walking++;
1199    item->wd->walking++;
1200    if (item->func.func)
1201      item->func.func((void *)item->func.data, item->wd->self, item);
1202    if (!item->delete_me)
1203      evas_object_smart_callback_call(item->wd->self, "selected", item);
1204    item->walking--;
1205    item->wd->walking--;
1206    if ((item->wd->clear_me) && (!item->wd->walking))
1207      elm_gengrid_clear(item->base.widget);
1208    else
1209      {
1210         if ((!item->walking) && (item->delete_me))
1211           if (!item->relcount) _item_del(item);
1212      }
1213    item->wd->last_selected_item = item;
1214 }
1215
1216 static void
1217 _item_unselect(Elm_Gengrid_Item *item)
1218 {
1219    if ((item->delete_me) || (!item->hilighted)) return;
1220    edje_object_signal_emit(item->base.view, "elm,state,unselected", "elm");
1221    item->hilighted = EINA_FALSE;
1222    if (item->selected)
1223      {
1224         item->selected = EINA_FALSE;
1225         item->wd->selected = eina_list_remove(item->wd->selected, item);
1226         evas_object_smart_callback_call(item->wd->self, "unselected", item);
1227      }
1228 }
1229
1230 static void
1231 _calc_job(void *data)
1232 {
1233    Widget_Data *wd = data;
1234    Evas_Coord minw = 0, minh = 0, nmax = 0, cvw, cvh;
1235    int count;
1236
1237    evas_object_geometry_get(wd->pan_smart, NULL, NULL, &cvw, &cvh);
1238    if ((wd->horizontal) && (wd->item_height > 0))
1239      nmax = cvh / wd->item_height;
1240    else if (wd->item_width > 0)
1241      nmax = cvw / wd->item_width;
1242
1243    if (nmax < 1)
1244      nmax = 1;
1245
1246    count = wd->count;
1247    if (wd->horizontal)
1248      {
1249         minw = ceil(count / (float)nmax) * wd->item_width;
1250         minh = nmax * wd->item_height;
1251      }
1252    else
1253      {
1254         minw = nmax * wd->item_width;
1255         minh = ceil(count / (float)nmax) * wd->item_height;
1256      }
1257
1258    if ((minw != wd->minw) || (minh != wd->minh))
1259      {
1260         wd->minh = minh;
1261         wd->minw = minw;
1262         evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
1263      }
1264
1265    wd->nmax = nmax;
1266    wd->calc_job = NULL;
1267    evas_object_smart_changed(wd->pan_smart);
1268 }
1269
1270 static void
1271 _pan_add(Evas_Object *obj)
1272 {
1273    Pan *sd;
1274    Evas_Object_Smart_Clipped_Data *cd;
1275
1276    _pan_sc.add(obj);
1277    cd = evas_object_smart_data_get(obj);
1278    sd = ELM_NEW(Pan);
1279    if (!sd) return;
1280    sd->__clipped_data = *cd;
1281    free(cd);
1282    evas_object_smart_data_set(obj, sd);
1283 }
1284
1285 static void
1286 _pan_del(Evas_Object *obj)
1287 {
1288    Pan *sd = evas_object_smart_data_get(obj);
1289
1290    if (!sd) return;
1291    _pan_sc.del(obj);
1292 }
1293
1294 static void
1295 _pan_set(Evas_Object *obj,
1296          Evas_Coord   x,
1297          Evas_Coord   y)
1298 {
1299    Pan *sd = evas_object_smart_data_get(obj);
1300    if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return;
1301    sd->wd->pan_x = x;
1302    sd->wd->pan_y = y;
1303    evas_object_smart_changed(obj);
1304 }
1305
1306 static void
1307 _pan_get(Evas_Object *obj,
1308          Evas_Coord  *x,
1309          Evas_Coord  *y)
1310 {
1311    Pan *sd = evas_object_smart_data_get(obj);
1312    if (x) *x = sd->wd->pan_x;
1313    if (y) *y = sd->wd->pan_y;
1314 }
1315
1316 static void
1317 _pan_child_size_get(Evas_Object *obj,
1318                     Evas_Coord  *w,
1319                     Evas_Coord  *h)
1320 {
1321    Pan *sd = evas_object_smart_data_get(obj);
1322    if (w) *w = sd->wd->minw;
1323    if (h) *h = sd->wd->minh;
1324 }
1325
1326 static void
1327 _pan_max_get(Evas_Object *obj,
1328              Evas_Coord  *x,
1329              Evas_Coord  *y)
1330 {
1331    Pan *sd = evas_object_smart_data_get(obj);
1332    Evas_Coord ow, oh;
1333
1334    if (!sd) return;
1335    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
1336    if (x)
1337      *x = (ow < sd->wd->minw) ? sd->wd->minw - ow : 0;
1338    if (y)
1339      *y = (oh < sd->wd->minh) ? sd->wd->minh - oh : 0;
1340 }
1341
1342 static void
1343 _pan_min_get(Evas_Object *obj,
1344              Evas_Coord  *x,
1345              Evas_Coord  *y)
1346 {
1347    Pan *sd = evas_object_smart_data_get(obj);
1348    Evas_Coord mx, my;
1349
1350    if (!sd) return;
1351    _pan_max_get(obj, &mx, &my);
1352    if (x)
1353      *x = -mx * sd->wd->align_x;
1354    if (y)
1355      *y = -my * sd->wd->align_y;
1356 }
1357
1358 static void
1359 _pan_resize(Evas_Object *obj,
1360             Evas_Coord   w,
1361             Evas_Coord   h)
1362 {
1363    Pan *sd = evas_object_smart_data_get(obj);
1364    Evas_Coord ow, oh;
1365
1366    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
1367    if ((ow == w) && (oh == h)) return;
1368    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
1369    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
1370 }
1371
1372 static void
1373 _pan_calculate(Evas_Object *obj)
1374 {
1375    Pan *sd = evas_object_smart_data_get(obj);
1376    Evas_Coord cx = 0, cy = 0;
1377    Elm_Gengrid_Item *item;
1378
1379    if (!sd) return;
1380    if (!sd->wd->nmax) return;
1381
1382    EINA_INLIST_FOREACH(sd->wd->items, item)
1383    {
1384       _item_place(item, cx, cy);
1385       if (sd->wd->horizontal)
1386         {
1387            cy = (cy + 1) % sd->wd->nmax;
1388            if (!cy) cx++;
1389         }
1390       else
1391         {
1392            cx = (cx + 1) % sd->wd->nmax;
1393            if (!cx) cy++;
1394         }
1395    }
1396    evas_object_smart_callback_call(sd->wd->self, "changed", NULL);
1397 }
1398
1399 static void
1400 _pan_move(Evas_Object *obj,
1401           Evas_Coord x __UNUSED__,
1402           Evas_Coord y __UNUSED__)
1403 {
1404    Pan *sd = evas_object_smart_data_get(obj);
1405    if (!sd) return;
1406    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
1407    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
1408 }
1409
1410 static void
1411 _hold_on(void *data       __UNUSED__,
1412          Evas_Object     *obj,
1413          void *event_info __UNUSED__)
1414 {
1415    Widget_Data *wd = elm_widget_data_get(obj);
1416    if (!wd) return;
1417    elm_smart_scroller_hold_set(wd->scr, 1);
1418 }
1419
1420 static void
1421 _hold_off(void *data       __UNUSED__,
1422           Evas_Object     *obj,
1423           void *event_info __UNUSED__)
1424 {
1425    Widget_Data *wd = elm_widget_data_get(obj);
1426    if (!wd) return;
1427    elm_smart_scroller_hold_set(wd->scr, 0);
1428 }
1429
1430 static void
1431 _freeze_on(void *data       __UNUSED__,
1432            Evas_Object     *obj,
1433            void *event_info __UNUSED__)
1434 {
1435    Widget_Data *wd = elm_widget_data_get(obj);
1436    if (!wd) return;
1437    elm_smart_scroller_freeze_set(wd->scr, 1);
1438 }
1439
1440 static void
1441 _freeze_off(void *data       __UNUSED__,
1442             Evas_Object     *obj,
1443             void *event_info __UNUSED__)
1444 {
1445    Widget_Data *wd = elm_widget_data_get(obj);
1446    if (!wd) return;
1447    elm_smart_scroller_freeze_set(wd->scr, 0);
1448 }
1449
1450 static void
1451 _scr_drag_start(void            *data,
1452                 Evas_Object *obj __UNUSED__,
1453                 void *event_info __UNUSED__)
1454 {
1455    evas_object_smart_callback_call(data, "scroll,drag,start", NULL);
1456 }
1457
1458 static void
1459 _scr_drag_stop(void            *data,
1460                Evas_Object *obj __UNUSED__,
1461                void *event_info __UNUSED__)
1462 {
1463    evas_object_smart_callback_call(data, "scroll,drag,stop", NULL);
1464 }
1465
1466 static void
1467 _scr_scroll(void            *data,
1468             Evas_Object *obj __UNUSED__,
1469             void *event_info __UNUSED__)
1470 {
1471    evas_object_smart_callback_call(data, "scroll", NULL);
1472 }
1473
1474 /**
1475  * Add a new Gengrid object.
1476  *
1477  * @param parent The parent object.
1478  * @return  The new object or NULL if it cannot be created.
1479  *
1480  * @see elm_gengrid_item_size_set()
1481  * @see elm_gengrid_horizontal_set()
1482  * @see elm_gengrid_item_append()
1483  * @see elm_gengrid_item_del()
1484  * @see elm_gengrid_clear()
1485  *
1486  * @ingroup Gengrid
1487  */
1488 EAPI Evas_Object *
1489 elm_gengrid_add(Evas_Object *parent)
1490 {
1491    Evas_Object *obj;
1492    Evas *e;
1493    Widget_Data *wd;
1494    static Evas_Smart *smart = NULL;
1495    Eina_Bool bounce = _elm_config->thumbscroll_bounce_enable;
1496
1497    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1498
1499    wd = ELM_NEW(Widget_Data);
1500    e = evas_object_evas_get(parent);
1501    if (!e) return NULL;
1502    obj = elm_widget_add(e);
1503    ELM_SET_WIDTYPE(widtype, "gengrid");
1504    elm_widget_type_set(obj, "gengrid");
1505    elm_widget_sub_object_add(parent, obj);
1506    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
1507    elm_widget_data_set(obj, wd);
1508    elm_widget_del_hook_set(obj, _del_hook);
1509    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
1510    elm_widget_theme_hook_set(obj, _theme_hook);
1511    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
1512    elm_widget_can_focus_set(obj, EINA_TRUE);
1513    elm_widget_event_hook_set(obj, _event_hook);
1514
1515    wd->scr = elm_smart_scroller_add(e);
1516    elm_smart_scroller_widget_set(wd->scr, obj);
1517    elm_smart_scroller_object_theme_set(obj, wd->scr, "gengrid", "base",
1518                                        "default");
1519    elm_widget_resize_object_set(obj, wd->scr);
1520
1521    evas_object_smart_callback_add(wd->scr, "drag,start", _scr_drag_start, obj);
1522    evas_object_smart_callback_add(wd->scr, "drag,stop", _scr_drag_stop, obj);
1523    evas_object_smart_callback_add(wd->scr, "scroll", _scr_scroll, obj);
1524
1525    elm_smart_scroller_bounce_allow_set(wd->scr, bounce, bounce);
1526
1527    wd->self = obj;
1528    wd->align_x = 0.5;
1529    wd->align_y = 0.5;
1530    wd->no_select = EINA_FALSE;
1531
1532    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
1533    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
1534    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
1535    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
1536
1537    if (!smart)
1538      {
1539         static Evas_Smart_Class sc;
1540
1541         evas_object_smart_clipped_smart_set(&_pan_sc);
1542         sc = _pan_sc;
1543         sc.name = "elm_gengrid_pan";
1544         sc.version = EVAS_SMART_CLASS_VERSION;
1545         sc.add = _pan_add;
1546         sc.del = _pan_del;
1547         sc.resize = _pan_resize;
1548         sc.move = _pan_move;
1549         sc.calculate = _pan_calculate;
1550         smart = evas_smart_class_new(&sc);
1551      }
1552    if (smart)
1553      {
1554         wd->pan_smart = evas_object_smart_add(e, smart);
1555         wd->pan = evas_object_smart_data_get(wd->pan_smart);
1556         wd->pan->wd = wd;
1557      }
1558
1559    elm_smart_scroller_extern_pan_set(wd->scr, wd->pan_smart,
1560                                      _pan_set, _pan_get, _pan_max_get,
1561                                      _pan_min_get, _pan_child_size_get);
1562
1563    return obj;
1564 }
1565
1566 /**
1567  * Set the size for the item of the Gengrid.
1568  *
1569  * @param obj The Gengrid object.
1570  * @param w The item's width.
1571  * @param h The item's height;
1572  *
1573  * @see elm_gengrid_item_size_get()
1574  *
1575  * @ingroup Gengrid
1576  */
1577 EAPI void
1578 elm_gengrid_item_size_set(Evas_Object *obj,
1579                           Evas_Coord   w,
1580                           Evas_Coord   h)
1581 {
1582    ELM_CHECK_WIDTYPE(obj, widtype);
1583    Widget_Data *wd = elm_widget_data_get(obj);
1584    if (!wd) return;
1585    if ((wd->item_width == w) && (wd->item_height == h)) return;
1586    wd->item_width = w;
1587    wd->item_height = h;
1588    if (wd->calc_job) ecore_job_del(wd->calc_job);
1589    wd->calc_job = ecore_job_add(_calc_job, wd);
1590 }
1591
1592 /**
1593  * Get the size of the item of the Gengrid.
1594  *
1595  * @param obj The Gengrid object.
1596  * @param w Pointer to the item's width.
1597  * @param h Pointer to the item's height.
1598  *
1599  * @see elm_gengrid_item_size_get()
1600  *
1601  * @ingroup Gengrid
1602  */
1603 EAPI void
1604 elm_gengrid_item_size_get(const Evas_Object *obj,
1605                           Evas_Coord        *w,
1606                           Evas_Coord        *h)
1607 {
1608    ELM_CHECK_WIDTYPE(obj, widtype);
1609    Widget_Data *wd = elm_widget_data_get(obj);
1610    if (!wd) return;
1611    if (w) *w = wd->item_width;
1612    if (h) *h = wd->item_height;
1613 }
1614
1615 /**
1616  * Set item's alignment within the scroller.
1617  *
1618  * @param obj The Gengrid object.
1619  * @param align_x The x alignment (0 <= x <= 1).
1620  * @param align_y The y alignment (0 <= y <= 1).
1621  *
1622  * @see elm_gengrid_align_get()
1623  *
1624  * @ingroup Gengrid
1625  */
1626 EAPI void
1627 elm_gengrid_align_set(Evas_Object *obj,
1628                       double       align_x,
1629                       double       align_y)
1630 {
1631    ELM_CHECK_WIDTYPE(obj, widtype);
1632    Widget_Data *wd = elm_widget_data_get(obj);
1633
1634    if (align_x > 1.0)
1635      align_x = 1.0;
1636    else if (align_x < 0.0)
1637      align_x = 0.0;
1638    wd->align_x = align_x;
1639
1640    if (align_y > 1.0)
1641      align_y = 1.0;
1642    else if (align_y < 0.0)
1643      align_y = 0.0;
1644    wd->align_y = align_y;
1645 }
1646
1647 /**
1648  * Get the alignenment set for the Gengrid object.
1649  *
1650  * @param obj The Gengrid object.
1651  * @param align_x Pointer to x alignenment.
1652  * @param align_y Pointer to y alignenment.
1653  *
1654  * @see elm_gengrid_align_set()
1655  *
1656  * @ingroup Gengrid
1657  */
1658 EAPI void
1659 elm_gengrid_align_get(const Evas_Object *obj,
1660                       double            *align_x,
1661                       double            *align_y)
1662 {
1663    ELM_CHECK_WIDTYPE(obj, widtype);
1664    Widget_Data *wd = elm_widget_data_get(obj);
1665    if (align_x) *align_x = wd->align_x;
1666    if (align_y) *align_y = wd->align_y;
1667 }
1668
1669 /**
1670  * Add item to the end of the Gengrid.
1671  *
1672  * @param obj The Gengrid object.
1673  * @param gic The item class for the item.
1674  * @param data The item data.
1675  * @param func Convenience function called when item is selected.
1676  * @param func_data Data passed to @p func above.
1677  * @return A handle to the item added or NULL if not possible.
1678  *
1679  * @see elm_gengrid_item_prepend()
1680  * @see elm_gengrid_item_insert_before()
1681  * @see elm_gengrid_item_insert_after()
1682  * @see elm_gengrid_item_del()
1683  *
1684  * @ingroup Gengrid
1685  */
1686 EAPI Elm_Gengrid_Item *
1687 elm_gengrid_item_append(Evas_Object                  *obj,
1688                         const Elm_Gengrid_Item_Class *gic,
1689                         const void                   *data,
1690                         Evas_Smart_Cb                 func,
1691                         const void                   *func_data)
1692 {
1693    Elm_Gengrid_Item *item;
1694    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1695    Widget_Data *wd = elm_widget_data_get(obj);
1696    if (!wd) return NULL;
1697
1698    item = _item_create(wd, gic, data, func, func_data);
1699    if (!item) return NULL;
1700    wd->items = eina_inlist_append(wd->items, EINA_INLIST_GET(item));
1701
1702    if (wd->calc_job) ecore_job_del(wd->calc_job);
1703    wd->calc_job = ecore_job_add(_calc_job, wd);
1704
1705    return item;
1706 }
1707
1708 /**
1709  * Add item at start of the Gengrid.
1710  *
1711  * This adds an item to the beginning of the grid.
1712  *
1713  * @param obj The Gengrid object.
1714  * @param gic The item class for the item.
1715  * @param data The item data.
1716  * @param func Convenience function called when item is selected.
1717  * @param func_data Data passed to @p func above.
1718  * @return A handle to the item added or NULL if not possible.
1719  *
1720  * @see elm_gengrid_item_append()
1721  * @see elm_gengrid_item_insert_before()
1722  * @see elm_gengrid_item_insert_after()
1723  * @see elm_gengrid_item_del()
1724  *
1725  * @ingroup Gengrid
1726  */
1727 EAPI Elm_Gengrid_Item *
1728 elm_gengrid_item_prepend(Evas_Object                  *obj,
1729                          const Elm_Gengrid_Item_Class *gic,
1730                          const void                   *data,
1731                          Evas_Smart_Cb                 func,
1732                          const void                   *func_data)
1733 {
1734    Elm_Gengrid_Item *item;
1735    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1736    Widget_Data *wd = elm_widget_data_get(obj);
1737    if (!wd) return NULL;
1738
1739    item = _item_create(wd, gic, data, func, func_data);
1740    if (!item) return NULL;
1741    wd->items = eina_inlist_prepend(wd->items, EINA_INLIST_GET(item));
1742
1743    if (wd->calc_job) ecore_job_del(wd->calc_job);
1744    wd->calc_job = ecore_job_add(_calc_job, wd);
1745
1746    return item;
1747 }
1748
1749 /**
1750  * Insert and item before another in the Gengrid.
1751  *
1752  * This inserts an item before another in the grid.
1753  *
1754  * @param obj The Gengrid object.
1755  * @param gic The item class for the item.
1756  * @param data The item data.
1757  * @param relative The item to which insert before.
1758  * @param func Convenience function called when item is selected.
1759  * @param func_data Data passed to @p func above.
1760  * @return A handle to the item added or NULL if not possible.
1761  *
1762  * @see elm_gengrid_item_append()
1763  * @see elm_gengrid_item_prepend()
1764  * @see elm_gengrid_item_insert_after()
1765  * @see elm_gengrid_item_del()
1766  *
1767  * @ingroup Gengrid
1768  */
1769 EAPI Elm_Gengrid_Item *
1770 elm_gengrid_item_insert_before(Evas_Object                  *obj,
1771                                const Elm_Gengrid_Item_Class *gic,
1772                                const void                   *data,
1773                                Elm_Gengrid_Item             *relative,
1774                                Evas_Smart_Cb                 func,
1775                                const void                   *func_data)
1776 {
1777    Elm_Gengrid_Item *item;
1778    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1779    EINA_SAFETY_ON_NULL_RETURN_VAL(relative, NULL);
1780    Widget_Data *wd = elm_widget_data_get(obj);
1781    if (!wd) return NULL;
1782
1783    item = _item_create(wd, gic, data, func, func_data);
1784    if (!item) return NULL;
1785    wd->items = eina_inlist_prepend_relative
1786        (wd->items, EINA_INLIST_GET(item), EINA_INLIST_GET(relative));
1787
1788    if (wd->calc_job) ecore_job_del(wd->calc_job);
1789    wd->calc_job = ecore_job_add(_calc_job, wd);
1790
1791    return item;
1792 }
1793
1794 /**
1795  * Insert and item after another in the Gengrid.
1796  *
1797  * This inserts an item after another in the grid.
1798  *
1799  * @param obj The Gengrid object.
1800  * @param gic The item class for the item.
1801  * @param data The item data.
1802  * @param relative The item to which insert after.
1803  * @param func Convenience function called when item is selected.
1804  * @param func_data Data passed to @p func above.
1805  * @return A handle to the item added or NULL if not possible.
1806  *
1807  * @see elm_gengrid_item_append()
1808  * @see elm_gengrid_item_prepend()
1809  * @see elm_gengrid_item_insert_before()
1810  * @see elm_gengrid_item_del()
1811  *
1812  * @ingroup Gengrid
1813  */
1814 EAPI Elm_Gengrid_Item *
1815 elm_gengrid_item_insert_after(Evas_Object                  *obj,
1816                               const Elm_Gengrid_Item_Class *gic,
1817                               const void                   *data,
1818                               Elm_Gengrid_Item             *relative,
1819                               Evas_Smart_Cb                 func,
1820                               const void                   *func_data)
1821 {
1822    Elm_Gengrid_Item *item;
1823    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1824    EINA_SAFETY_ON_NULL_RETURN_VAL(relative, NULL);
1825    Widget_Data *wd = elm_widget_data_get(obj);
1826    if (!wd) return NULL;
1827
1828    item = _item_create(wd, gic, data, func, func_data);
1829    if (!item) return NULL;
1830    wd->items = eina_inlist_append_relative
1831        (wd->items, EINA_INLIST_GET(item), EINA_INLIST_GET(relative));
1832
1833    if (wd->calc_job) ecore_job_del(wd->calc_job);
1834    wd->calc_job = ecore_job_add(_calc_job, wd);
1835
1836    return item;
1837 }
1838
1839 /**
1840  * Remove a item from the Gengrid.
1841  *
1842  * @param item The item to be removed.
1843  * @return @c EINA_TRUE on success or @c EINA_FALSE otherwise.
1844  *
1845  * @see elm_gengrid_clear() to remove all items of the Gengrid.
1846  *
1847  * @ingroup Gengrid
1848  */
1849 EAPI void
1850 elm_gengrid_item_del(Elm_Gengrid_Item *item)
1851 {
1852    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
1853    if ((item->relcount > 0) || (item->walking > 0))
1854      {
1855         item->delete_me = EINA_TRUE;
1856         elm_widget_item_pre_notify_del(item);
1857         if (item->selected)
1858           item->wd->selected = eina_list_remove(item->wd->selected, item);
1859         if (item->gic->func.del)
1860           item->gic->func.del((void *)item->base.data, item->wd->self);
1861         return;
1862      }
1863
1864    _item_del(item);
1865 }
1866
1867 /**
1868  * Set for what direction the Gengrid will expand.
1869  *
1870  * @param obj The Gengrid object.
1871  * @param setting If @c EINA_TRUE the Gengrid will expand horizontally
1872  * or vertically if @c EINA_FALSE.
1873  *
1874  * @ingroup Gengrid
1875  */
1876 EAPI void
1877 elm_gengrid_horizontal_set(Evas_Object *obj,
1878                            Eina_Bool    setting)
1879 {
1880    ELM_CHECK_WIDTYPE(obj, widtype);
1881    Widget_Data *wd = elm_widget_data_get(obj);
1882    if (!wd) return;
1883    if (setting == wd->horizontal) return;
1884    wd->horizontal = setting;
1885
1886    /* Update the items to conform to the new layout */
1887    if (wd->calc_job) ecore_job_del(wd->calc_job);
1888    wd->calc_job = ecore_job_add(_calc_job, wd);
1889 }
1890
1891 /**
1892  * Clear the Gengrid
1893  *
1894  * This clears all items in the Gengrid, leaving it empty.
1895  *
1896  * @param obj The Gengrid object.
1897  *
1898  * @see elm_gengrid_item_del() to remove just one item.
1899  *
1900  * @ingroup Gengrid
1901  */
1902 EAPI void
1903 elm_gengrid_clear(Evas_Object *obj)
1904 {
1905    ELM_CHECK_WIDTYPE(obj, widtype);
1906    Widget_Data *wd = elm_widget_data_get(obj);
1907    if (!wd) return;
1908
1909    if (wd->calc_job)
1910      {
1911         ecore_job_del(wd->calc_job);
1912         wd->calc_job = NULL;
1913      }
1914
1915    if (wd->walking > 0)
1916      {
1917         Elm_Gengrid_Item *item;
1918         wd->clear_me = 1;
1919         EINA_INLIST_FOREACH(wd->items, item)
1920         item->delete_me = 1;
1921         return;
1922      }
1923    wd->clear_me = 0;
1924    while (wd->items)
1925      {
1926         Elm_Gengrid_Item *item = ELM_GENGRID_ITEM_FROM_INLIST(wd->items);
1927
1928         wd->items = eina_inlist_remove(wd->items, wd->items);
1929         elm_widget_item_pre_notify_del(item);
1930         if (item->realized) _item_unrealize(item);
1931         if (item->gic->func.del)
1932           item->gic->func.del((void *)item->base.data, wd->self);
1933         if (item->long_timer) ecore_timer_del(item->long_timer);
1934         elm_widget_item_del(item);
1935      }
1936
1937    if (wd->selected)
1938      {
1939         eina_list_free(wd->selected);
1940         wd->selected = NULL;
1941      }
1942
1943    wd->pan_x = 0;
1944    wd->pan_y = 0;
1945    wd->minw = 0;
1946    wd->minh = 0;
1947    wd->count = 0;
1948    evas_object_size_hint_min_set(wd->pan_smart, wd->minw, wd->minh);
1949    evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
1950 }
1951
1952 /**
1953  * Get the real evas object of the Gengrid item
1954  *
1955  * This returns the actual evas object used for the specified Gengrid
1956  * item.  This may be NULL as it may not be created, and may be
1957  * deleted at any time by Gengrid. Do not modify this object (move,
1958  * resize, show, hide etc.) as Gengrid is controlling it. This
1959  * function is for querying, emitting custom signals or hooking lower
1960  * level callbacks for events. Do not delete this object under any
1961  * circumstances.
1962  *
1963  * @param item The Gengrid item.
1964  * @return the evas object associated to this item.
1965  *
1966  * @see elm_gengrid_item_data_get()
1967  *
1968  * @ingroup Gengrid
1969  */
1970 EAPI const Evas_Object *
1971 elm_gengrid_item_object_get(const Elm_Gengrid_Item *item)
1972 {
1973    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
1974    return item->base.view;
1975 }
1976
1977 /**
1978  * Update the contents of an item
1979  *
1980  * This updates an item by calling all the item class functions again
1981  * to get the icons, labels and states. Use this when the original
1982  * item data has changed and the changes are desired to be reflected.
1983  *
1984  * @param item The item
1985  *
1986  * @ingroup Gengrid
1987  */
1988 EAPI void
1989 elm_gengrid_item_update(Elm_Gengrid_Item *item)
1990 {
1991    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
1992    if (!item->realized) return;
1993    if (item->want_unrealize) return;
1994    _item_unrealize(item);
1995    _item_realize(item);
1996    _item_place(item, item->x, item->y);
1997 }
1998
1999 /**
2000  * Returns the data associated to a item
2001  *
2002  * This returns the data value passed on the elm_gengrid_item_append()
2003  * and related item addition calls.
2004  *
2005  * @param item The Gengrid item.
2006  * @return the data associated to this item.
2007  *
2008  * @see elm_gengrid_item_append()
2009  * @see elm_gengrid_item_object_get()
2010  *
2011  * @ingroup Gengrid
2012  */
2013 EAPI void *
2014 elm_gengrid_item_data_get(const Elm_Gengrid_Item *item)
2015 {
2016    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
2017    return elm_widget_item_data_get(item);
2018 }
2019
2020 /**
2021  * Set the data item from the gengrid item
2022  *
2023  * This set the data value passed on the elm_gengrid_item_append() and
2024  * related item addition calls. This function will also call
2025  * elm_gengrid_item_update() so the item will be updated to reflect
2026  * the new data.
2027  *
2028  * @param item The item
2029  * @param data The new data pointer to set
2030  *
2031  * @ingroup Gengrid
2032  */
2033 EAPI void
2034 elm_gengrid_item_data_set(Elm_Gengrid_Item *item,
2035                           const void       *data)
2036 {
2037    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
2038    elm_widget_item_data_set(item, data);
2039    elm_gengrid_item_update(item);
2040 }
2041
2042 /**
2043  * Get the item's coordinates.
2044  *
2045  * This returns the logical position of the item whithin the Gengrid.
2046  *
2047  * @param item The Gengrid item.
2048  * @param x The x-axis coordinate pointer.
2049  * @param y The y-axis coordinate pointer.
2050  *
2051  * @ingroup Gengrid
2052  */
2053 EAPI void
2054 elm_gengrid_item_pos_get(const Elm_Gengrid_Item *item,
2055                          unsigned int           *x,
2056                          unsigned int           *y)
2057 {
2058    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
2059    if (x) *x = item->x;
2060    if (y) *y = item->y;
2061 }
2062
2063 /**
2064  * Enable or disable multi-select in the Gengrid.
2065  *
2066  * This enables (EINA_TRUE) or disables (EINA_FALSE) multi-select in
2067  * the Gengrid.  This allows more than 1 item to be selected.
2068  *
2069  * @param obj The Gengrid object.
2070  * @param multi Multi-select enabled/disabled
2071  *
2072  * @ingroup Gengrid
2073  */
2074 EAPI void
2075 elm_gengrid_multi_select_set(Evas_Object *obj,
2076                              Eina_Bool    multi)
2077 {
2078    ELM_CHECK_WIDTYPE(obj, widtype);
2079    Widget_Data *wd = elm_widget_data_get(obj);
2080    if (!wd) return;
2081    wd->multi = multi;
2082 }
2083
2084 /**
2085  * Get if multi-select in Gengrid is enabled or disabled
2086  *
2087  * @param obj The Gengrid object
2088  * @return Multi-select enable/disable
2089  * (EINA_TRUE = enabled / EINA_FALSE = disabled)
2090  *
2091  * @ingroup Gengrid
2092  */
2093 EAPI Eina_Bool
2094 elm_gengrid_multi_select_get(const Evas_Object *obj)
2095 {
2096    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2097    Widget_Data *wd = elm_widget_data_get(obj);
2098    if (!wd) return EINA_FALSE;
2099    return wd->multi;
2100 }
2101
2102 /**
2103  * Get the selected item in the Gengrid
2104  *
2105  * This gets the selected item in the Gengrid (if multi-select is
2106  * enabled only the first item in the list is selected - which is not
2107  * very useful, so see elm_gengrid_selected_items_get() for when
2108  * multi-select is used).
2109  *
2110  * If no item is selected, NULL is returned.
2111  *
2112  * @param obj The Gengrid object.
2113  * @return The selected item, or NULL if none.
2114  *
2115  * @ingroup Gengrid
2116  */
2117 EAPI Elm_Gengrid_Item *
2118 elm_gengrid_selected_item_get(const Evas_Object *obj)
2119 {
2120    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2121    Widget_Data *wd = elm_widget_data_get(obj);
2122    if (!wd) return NULL;
2123    if (wd->selected) return wd->selected->data;
2124    return NULL;
2125 }
2126
2127 /**
2128  * Get a list of selected items in the Gengrid.
2129  *
2130  * This returns a list of the selected items. This list pointer is
2131  * only valid so long as no items are selected or unselected (or
2132  * unselected implictly by deletion). The list contains
2133  * Elm_Gengrid_Item pointers.
2134  *
2135  * @param obj The Gengrid object.
2136  * @return The list of selected items, or NULL if none are selected.
2137  *
2138  * @ingroup Gengrid
2139  */
2140 EAPI const Eina_List *
2141 elm_gengrid_selected_items_get(const Evas_Object *obj)
2142 {
2143    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2144    Widget_Data *wd = elm_widget_data_get(obj);
2145    if (!wd) return NULL;
2146    return wd->selected;
2147 }
2148
2149 /**
2150  * Set the selected state of a item.
2151  *
2152  * This sets the selected state of a item. If multi-select is not
2153  * enabled and selected is EINA_TRUE, previously selected items are
2154  * unselected.
2155  *
2156  * @param item The item
2157  * @param selected The selected state.
2158  *
2159  * @ingroup Gengrid
2160  */
2161 EAPI void
2162 elm_gengrid_item_selected_set(Elm_Gengrid_Item *item,
2163                               Eina_Bool         selected)
2164 {
2165    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
2166    Widget_Data *wd = item->wd;
2167    if (!wd) return;
2168    if ((!item) || (item->delete_me)) return;
2169    selected = !!selected;
2170    if (item->selected == selected) return;
2171
2172    if (selected)
2173      {
2174         if (!wd->multi)
2175           {
2176              while (wd->selected)
2177                _item_unselect(wd->selected->data);
2178           }
2179         _item_hilight(item);
2180         _item_select(item);
2181      }
2182    else
2183      _item_unselect(item);
2184 }
2185
2186 /**
2187  * Get the selected state of a item.
2188  *
2189  * This gets the selected state of a item (1 selected, 0 not selected).
2190  *
2191  * @param item The item
2192  * @return The selected state
2193  *
2194  * @ingroup Gengrid
2195  */
2196 EAPI Eina_Bool
2197 elm_gengrid_item_selected_get(const Elm_Gengrid_Item *item)
2198 {
2199    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, EINA_FALSE);
2200    return item->selected;
2201 }
2202
2203 /**
2204  * Sets the disabled state of a item.
2205  *
2206  * A disabled item cannot be selected or unselected. It will also
2207  * change appearance to disabled. This sets the disabled state (1
2208  * disabled, 0 not disabled).
2209  *
2210  * @param item The item
2211  * @param disabled The disabled state
2212  *
2213  * @ingroup Gengrid
2214  */
2215 EAPI void
2216 elm_gengrid_item_disabled_set(Elm_Gengrid_Item *item,
2217                               Eina_Bool         disabled)
2218 {
2219    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
2220    if (item->disabled == disabled) return;
2221    if (item->delete_me) return;
2222    item->disabled = disabled;
2223    if (item->realized)
2224      {
2225         if (item->disabled)
2226           edje_object_signal_emit(item->base.view, "elm,state,disabled", "elm");
2227         else
2228           edje_object_signal_emit(item->base.view, "elm,state,enabled", "elm");
2229      }
2230 }
2231
2232 /**
2233  * Get the disabled state of a item.
2234  *
2235  * This gets the disabled state of the given item.
2236  *
2237  * @param item The item
2238  * @return The disabled state
2239  *
2240  * @ingroup Gengrid
2241  */
2242 EAPI Eina_Bool
2243 elm_gengrid_item_disabled_get(const Elm_Gengrid_Item *item)
2244 {
2245    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, EINA_FALSE);
2246    if (item->delete_me) return EINA_FALSE;
2247    return item->disabled;
2248 }
2249
2250 static Evas_Object *
2251 _elm_gengrid_item_label_create(void        *data,
2252                                Evas_Object *obj,
2253                                void *item   __UNUSED__)
2254 {
2255    Evas_Object *label = elm_label_add(obj);
2256    if (!label)
2257      return NULL;
2258    elm_object_style_set(label, "tooltip");
2259    elm_label_label_set(label, data);
2260    return label;
2261 }
2262
2263 static void
2264 _elm_gengrid_item_label_del_cb(void            *data,
2265                                Evas_Object *obj __UNUSED__,
2266                                void *event_info __UNUSED__)
2267 {
2268    eina_stringshare_del(data);
2269 }
2270
2271 /**
2272  * Set the text to be shown in the gengrid item.
2273  *
2274  * @param item Target item
2275  * @param text The text to set in the content
2276  *
2277  * Setup the text as tooltip to object. The item can have only one
2278  * tooltip, so any previous tooltip data is removed.
2279  *
2280  * @ingroup Gengrid
2281  */
2282 EAPI void
2283 elm_gengrid_item_tooltip_text_set(Elm_Gengrid_Item *item,
2284                                   const char       *text)
2285 {
2286    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
2287    text = eina_stringshare_add(text);
2288    elm_gengrid_item_tooltip_content_cb_set(item, _elm_gengrid_item_label_create,
2289                                            text,
2290                                            _elm_gengrid_item_label_del_cb);
2291 }
2292
2293 /**
2294  * Set the content to be shown in the tooltip item
2295  *
2296  * Setup the tooltip to item. The item can have only one tooltip, so
2297  * any previous tooltip data is removed. @p func(with @p data) will be
2298  * called every time that need show the tooltip and it should return a
2299  * valid Evas_Object. This object is then managed fully by tooltip
2300  * system and is deleted when the tooltip is gone.
2301  *
2302  * @param item the gengrid item being attached a tooltip.
2303  * @param func the function used to create the tooltip contents.
2304  * @param data what to provide to @a func as callback data/context.
2305  * @param del_cb called when data is not needed anymore, either when
2306  *        another callback replaces @func, the tooltip is unset with
2307  *        elm_gengrid_item_tooltip_unset() or the owner @a item
2308  *        dies. This callback receives as the first parameter the
2309  *        given @a data, and @c event_info is the item.
2310  *
2311  * @ingroup Gengrid
2312  */
2313 EAPI void
2314 elm_gengrid_item_tooltip_content_cb_set(Elm_Gengrid_Item           *item,
2315                                         Elm_Tooltip_Item_Content_Cb func,
2316                                         const void                 *data,
2317                                         Evas_Smart_Cb               del_cb)
2318 {
2319    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_GOTO(item, error);
2320
2321    if ((item->tooltip.content_cb == func) && (item->tooltip.data == data))
2322      return;
2323
2324    if (item->tooltip.del_cb)
2325      item->tooltip.del_cb((void *)item->tooltip.data,
2326                           item->base.widget, item);
2327    item->tooltip.content_cb = func;
2328    item->tooltip.data = data;
2329    item->tooltip.del_cb = del_cb;
2330    if (item->base.view)
2331      {
2332         elm_widget_item_tooltip_content_cb_set(item,
2333                                                item->tooltip.content_cb,
2334                                                item->tooltip.data, NULL);
2335         elm_widget_item_tooltip_style_set(item, item->tooltip.style);
2336      }
2337
2338    return;
2339
2340 error:
2341    if (del_cb) del_cb((void *)data, NULL, NULL);
2342 }
2343
2344 /**
2345  * Unset tooltip from item
2346  *
2347  * @param item gengrid item to remove previously set tooltip.
2348  *
2349  * Remove tooltip from item. The callback provided as del_cb to
2350  * elm_gengrid_item_tooltip_content_cb_set() will be called to notify
2351  * it is not used anymore.
2352  *
2353  * @see elm_gengrid_item_tooltip_content_cb_set()
2354  *
2355  * @ingroup Gengrid
2356  */
2357 EAPI void
2358 elm_gengrid_item_tooltip_unset(Elm_Gengrid_Item *item)
2359 {
2360    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
2361    if ((item->base.view) && (item->tooltip.content_cb))
2362      elm_widget_item_tooltip_unset(item);
2363
2364    if (item->tooltip.del_cb)
2365      item->tooltip.del_cb((void *)item->tooltip.data, item->base.widget, item);
2366    item->tooltip.del_cb = NULL;
2367    item->tooltip.content_cb = NULL;
2368    item->tooltip.data = NULL;
2369    if (item->tooltip.style)
2370      elm_gengrid_item_tooltip_style_set(item, NULL);
2371 }
2372
2373 /**
2374  * Sets a different style for this item tooltip.
2375  *
2376  * @note before you set a style you should define a tooltip with
2377  *       elm_gengrid_item_tooltip_content_cb_set() or
2378  *       elm_gengrid_item_tooltip_text_set()
2379  *
2380  * @param item gengrid item with tooltip already set.
2381  * @param style the theme style to use (default, transparent, ...)
2382  *
2383  * @ingroup Gengrid
2384  */
2385 EAPI void
2386 elm_gengrid_item_tooltip_style_set(Elm_Gengrid_Item *item,
2387                                    const char       *style)
2388 {
2389    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
2390    eina_stringshare_replace(&item->tooltip.style, style);
2391    if (item->base.view) elm_widget_item_tooltip_style_set(item, style);
2392 }
2393
2394 /**
2395  * Get the style for this item tooltip.
2396  *
2397  * @param item gengrid item with tooltip already set.
2398  * @return style the theme style in use, defaults to "default". If the
2399  *         object does not have a tooltip set, then NULL is returned.
2400  *
2401  * @ingroup Gengrid
2402  */
2403 EAPI const char *
2404 elm_gengrid_item_tooltip_style_get(const Elm_Gengrid_Item *item)
2405 {
2406    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
2407    return item->tooltip.style;
2408 }
2409
2410 /**
2411  * Set the cursor to be shown when mouse is over the gengrid item
2412  *
2413  * @param item Target item
2414  * @param cursor the cursor name to be used.
2415  *
2416  * @see elm_object_cursor_set()
2417  * @ingroup Gengrid
2418  */
2419 EAPI void
2420 elm_gengrid_item_cursor_set(Elm_Gengrid_Item *item,
2421                             const char       *cursor)
2422 {
2423    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
2424    eina_stringshare_replace(&item->mouse_cursor, cursor);
2425    if (item->base.view) elm_widget_item_cursor_set(item, cursor);
2426 }
2427
2428 /**
2429  * Get the cursor to be shown when mouse is over the gengrid item
2430  *
2431  * @param item gengrid item with cursor already set.
2432  * @return the cursor name.
2433  *
2434  * @ingroup Gengrid
2435  */
2436 EAPI const char *
2437 elm_gengrid_item_cursor_get(const Elm_Gengrid_Item *item)
2438 {
2439    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
2440    return elm_widget_item_cursor_get(item);
2441 }
2442
2443 /**
2444  * Unset the cursor to be shown when mouse is over the gengrid item
2445  *
2446  * @param item Target item
2447  *
2448  * @see elm_object_cursor_unset()
2449  * @ingroup Gengrid
2450  */
2451 EAPI void
2452 elm_gengrid_item_cursor_unset(Elm_Gengrid_Item *item)
2453 {
2454    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
2455    if (!item->mouse_cursor)
2456      return;
2457
2458    if (item->base.view)
2459      elm_widget_item_cursor_unset(item);
2460
2461    eina_stringshare_del(item->mouse_cursor);
2462    item->mouse_cursor = NULL;
2463 }
2464
2465 /**
2466  * Sets a different style for this item cursor.
2467  *
2468  * @note before you set a style you should define a cursor with
2469  *       elm_gengrid_item_cursor_set()
2470  *
2471  * @param item gengrid item with cursor already set.
2472  * @param style the theme style to use (default, transparent, ...)
2473  *
2474  * @ingroup Gengrid
2475  */
2476 EAPI void
2477 elm_gengrid_item_cursor_style_set(Elm_Gengrid_Item *item,
2478                                   const char       *style)
2479 {
2480    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
2481    elm_widget_item_cursor_style_set(item, style);
2482 }
2483
2484 /**
2485  * Get the style for this item cursor.
2486  *
2487  * @param item gengrid item with cursor already set.
2488  * @return style the theme style in use, defaults to "default". If the
2489  *         object does not have a cursor set, then NULL is returned.
2490  *
2491  * @ingroup Gengrid
2492  */
2493 EAPI const char *
2494 elm_gengrid_item_cursor_style_get(const Elm_Gengrid_Item *item)
2495 {
2496    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
2497    return elm_widget_item_cursor_style_get(item);
2498 }
2499
2500 /**
2501  * Set if the cursor set should be searched on the theme or should use
2502  * the provided by the engine, only.
2503  *
2504  * @note before you set if should look on theme you should define a
2505  * cursor with elm_object_cursor_set(). By default it will only look
2506  * for cursors provided by the engine.
2507  *
2508  * @param item widget item with cursor already set.
2509  * @param engine_only boolean to define it cursors should be looked
2510  * only between the provided by the engine or searched on widget's
2511  * theme as well.
2512  *
2513  * @ingroup Gengrid
2514  */
2515 EAPI void
2516 elm_gengrid_item_cursor_engine_only_set(Elm_Gengrid_Item *item,
2517                                         Eina_Bool         engine_only)
2518 {
2519    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
2520    elm_widget_item_cursor_engine_only_set(item, engine_only);
2521 }
2522
2523 /**
2524  * Get the cursor engine only usage for this item cursor.
2525  *
2526  * @param item widget item with cursor already set.
2527  * @return engine_only boolean to define it cursors should be looked
2528  * only between the provided by the engine or searched on widget's
2529  * theme as well. If the object does not have a cursor set, then
2530  * EINA_FALSE is returned.
2531  *
2532  * @ingroup Gengrid
2533  */
2534 EAPI Eina_Bool
2535 elm_gengrid_item_cursor_engine_only_get(const Elm_Gengrid_Item *item)
2536 {
2537    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, EINA_FALSE);
2538    return elm_widget_item_cursor_engine_only_get(item);
2539 }
2540
2541 /**
2542  * Set the always select mode.
2543  *
2544  * Cells will only call their selection func and callback when first
2545  * becoming selected. Any further clicks will do nothing, unless you
2546  * enable always select with
2547  * elm_gengrid_always_select_mode_set(). This means even if selected,
2548  * every click will make the selected callbacks be called.
2549  *
2550  * @param obj The Gengrid object
2551  * @param always_select The always select mode (EINA_TRUE = on,
2552  * EINA_FALSE = off)
2553  *
2554  * @ingroup Gengrid
2555  */
2556 EAPI void
2557 elm_gengrid_always_select_mode_set(Evas_Object *obj,
2558                                    Eina_Bool    always_select)
2559 {
2560    ELM_CHECK_WIDTYPE(obj, widtype);
2561    Widget_Data *wd = elm_widget_data_get(obj);
2562    if (!wd) return;
2563    wd->always_select = always_select;
2564 }
2565
2566 /**
2567  * Get the always select mode.
2568  *
2569  * @param obj The Gengrid object.
2570  * @return The always select mode (EINA_TRUE = on, EINA_FALSE = off)
2571  *
2572  * @ingroup Gengrid
2573  */
2574 EAPI Eina_Bool
2575 elm_gengrid_always_select_mode_get(const Evas_Object *obj)
2576 {
2577    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2578    Widget_Data *wd = elm_widget_data_get(obj);
2579    if (!wd) return EINA_FALSE;
2580    return wd->always_select;
2581 }
2582
2583 /**
2584  * Set no select mode.
2585  *
2586  * This will turn off the ability to select items entirely and they
2587  * will neither appear selected nor call selected callback functions.
2588  *
2589  * @param obj The Gengrid object
2590  * @param no_select The no select mode (EINA_TRUE = on, EINA_FALSE = off)
2591  *
2592  * @ingroup Gengrid
2593  */
2594 EAPI void
2595 elm_gengrid_no_select_mode_set(Evas_Object *obj,
2596                                Eina_Bool    no_select)
2597 {
2598    ELM_CHECK_WIDTYPE(obj, widtype);
2599    Widget_Data *wd = elm_widget_data_get(obj);
2600    if (!wd) return;
2601    wd->no_select = no_select;
2602 }
2603
2604 /**
2605  * Gets no select mode.
2606  *
2607  * @param obj The Gengrid object
2608  * @return The no select mode (EINA_TRUE = on, EINA_FALSE = off)
2609  *
2610  * @ingroup Gengrid
2611  */
2612 EAPI Eina_Bool
2613 elm_gengrid_no_select_mode_get(const Evas_Object *obj)
2614 {
2615    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2616    Widget_Data *wd = elm_widget_data_get(obj);
2617    if (!wd) return EINA_FALSE;
2618    return wd->no_select;
2619 }
2620
2621 /**
2622  * Set bounce mode.
2623  *
2624  * This will enable or disable the scroller bounce mode for the
2625  * Gengrid. See elm_scroller_bounce_set() for details.
2626  *
2627  * @param obj The Gengrid object
2628  * @param h_bounce Allow bounce horizontally
2629  * @param v_bounce Allow bounce vertically
2630  *
2631  * @ingroup Gengrid
2632  */
2633 EAPI void
2634 elm_gengrid_bounce_set(Evas_Object *obj,
2635                        Eina_Bool    h_bounce,
2636                        Eina_Bool    v_bounce)
2637 {
2638    ELM_CHECK_WIDTYPE(obj, widtype);
2639    Widget_Data *wd = elm_widget_data_get(obj);
2640    if (!wd) return;
2641    elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
2642 }
2643
2644 /**
2645  * Get the bounce mode
2646  *
2647  * @param obj The Gengrid object
2648  * @param h_bounce Allow bounce horizontally
2649  * @param v_bounce Allow bounce vertically
2650  *
2651  * @ingroup Gengrid
2652  */
2653 EAPI void
2654 elm_gengrid_bounce_get(const Evas_Object *obj,
2655                        Eina_Bool         *h_bounce,
2656                        Eina_Bool         *v_bounce)
2657 {
2658    ELM_CHECK_WIDTYPE(obj, widtype);
2659    Widget_Data *wd = elm_widget_data_get(obj);
2660    if (!wd) return;
2661    elm_smart_scroller_bounce_allow_get(wd->scr, h_bounce, v_bounce);
2662 }
2663
2664 /**
2665  * Get all items in the Gengrid.
2666  *
2667  * This returns a list of the Gengrid items. The list contains
2668  * Elm_Gengrid_Item pointers.
2669  *
2670  * @param obj The Gengrid object.
2671  * @return The list of items, or NULL if none.
2672  *
2673  * @ingroup Gengrid
2674  */
2675
2676 /**
2677  * Set gengrid scroll page size relative to viewport size.
2678  *
2679  * The gengrid scroller is capable of limiting scrolling by the user
2680  * to "pages" That is to jump by and only show a "whole page" at a
2681  * time as if the continuous area of the scroller content is split
2682  * into page sized pieces.  This sets the size of a page relative to
2683  * the viewport of the scroller. 1.0 is "1 viewport" is size
2684  * (horizontally or vertically). 0.0 turns it off in that axis. This
2685  * is mutually exclusive with page size (see
2686  * elm_gengrid_page_size_set() for more information). Likewise 0.5 is
2687  * "half a viewport". Sane usable valus are normally between 0.0 and
2688  * 1.0 including 1.0. If you only want 1 axis to be page "limited",
2689  * use 0.0 for the other axis.
2690  *
2691  * @param obj The gengrid object
2692  * @param h_pagerel The horizontal page relative size
2693  * @param v_pagerel The vertical page relative size
2694  *
2695  * @ingroup Gengrid
2696  */
2697 EAPI void
2698 elm_gengrid_page_relative_set(Evas_Object *obj,
2699                               double       h_pagerel,
2700                               double       v_pagerel)
2701 {
2702    Evas_Coord pagesize_h;
2703    Evas_Coord pagesize_v;
2704
2705    ELM_CHECK_WIDTYPE(obj, widtype);
2706    Widget_Data *wd = elm_widget_data_get(obj);
2707    if (!wd) return;
2708
2709    elm_smart_scroller_paging_get(wd->scr, NULL, NULL, &pagesize_h, &pagesize_v);
2710    elm_smart_scroller_paging_set(wd->scr, h_pagerel, v_pagerel, pagesize_h,
2711                                  pagesize_v);
2712 }
2713
2714 /**
2715  * Set gengrid scroll page size.
2716  *
2717  * See also elm_gengrid_page_relative_set(). This, instead of a page
2718  * size being relative to the viewport, sets it to an absolute fixed
2719  * value, with 0 turning it off for that axis.
2720  *
2721  * @param obj The gengrid object
2722  * @param h_pagesize The horizontal page size
2723  * @param v_pagesize The vertical page size
2724  *
2725  * @ingroup Gengrid
2726  */
2727 EAPI void
2728 elm_gengrid_page_size_set(Evas_Object *obj,
2729                           Evas_Coord   h_pagesize,
2730                           Evas_Coord   v_pagesize)
2731 {
2732    double pagerel_h;
2733    double pagerel_v;
2734
2735    ELM_CHECK_WIDTYPE(obj, widtype);
2736    Widget_Data *wd = elm_widget_data_get(obj);
2737    if (!wd) return;
2738    elm_smart_scroller_paging_get(wd->scr, &pagerel_h, &pagerel_v, NULL, NULL);
2739    elm_smart_scroller_paging_set(wd->scr, pagerel_h, pagerel_v, h_pagesize,
2740                                  v_pagesize);
2741 }
2742
2743 /**
2744  * Get the first item in the gengrid
2745  *
2746  * This returns the first item in the list.
2747  *
2748  * @param obj The gengrid object
2749  * @return The first item, or NULL if none
2750  *
2751  * @ingroup Gengrid
2752  */
2753 EAPI Elm_Gengrid_Item *
2754 elm_gengrid_first_item_get(const Evas_Object *obj)
2755 {
2756    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2757    Widget_Data *wd = elm_widget_data_get(obj);
2758    if (!wd) return NULL;
2759    if (!wd->items) return NULL;
2760    Elm_Gengrid_Item *item = ELM_GENGRID_ITEM_FROM_INLIST(wd->items);
2761    while ((item) && (item->delete_me))
2762      item = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(item)->next);
2763    return item;
2764 }
2765
2766 /**
2767  * Get the last item in the gengrid
2768  *
2769  * This returns the last item in the list.
2770  *
2771  * @return The last item, or NULL if none
2772  *
2773  * @ingroup Gengrid
2774  */
2775 EAPI Elm_Gengrid_Item *
2776 elm_gengrid_last_item_get(const Evas_Object *obj)
2777 {
2778    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2779    Widget_Data *wd = elm_widget_data_get(obj);
2780    if (!wd->items) return NULL;
2781    Elm_Gengrid_Item *item = ELM_GENGRID_ITEM_FROM_INLIST(wd->items->last);
2782    if (!wd) return NULL;
2783    while ((item) && (item->delete_me))
2784      item = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(item)->prev);
2785    return item;
2786 }
2787
2788 /**
2789  * Get the next item in the gengrid
2790  *
2791  * This returns the item after the item @p item.
2792  *
2793  * @param item The item
2794  * @return The item after @p item, or NULL if none
2795  *
2796  * @ingroup Gengrid
2797  */
2798 EAPI Elm_Gengrid_Item *
2799 elm_gengrid_item_next_get(const Elm_Gengrid_Item *item)
2800 {
2801    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
2802    while (item)
2803      {
2804         item = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(item)->next);
2805         if ((item) && (!item->delete_me)) break;
2806      }
2807    return (Elm_Gengrid_Item *)item;
2808 }
2809
2810 /**
2811  * Get the previous item in the gengrid
2812  *
2813  * This returns the item before the item @p item.
2814  *
2815  * @param item The item
2816  * @return The item before @p item, or NULL if none
2817  *
2818  * @ingroup Gengrid
2819  */
2820 EAPI Elm_Gengrid_Item *
2821 elm_gengrid_item_prev_get(const Elm_Gengrid_Item *item)
2822 {
2823    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
2824    while (item)
2825      {
2826         item = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(item)->prev);
2827         if ((item) && (!item->delete_me)) break;
2828      }
2829    return (Elm_Gengrid_Item *)item;
2830 }
2831
2832 /**
2833  * Get the gengrid object from an item
2834  *
2835  * This returns the gengrid object itself that an item belongs to.
2836  *
2837  * @param item The item
2838  * @return The gengrid object
2839  *
2840  * @ingroup Gengrid
2841  */
2842 EAPI Evas_Object *
2843 elm_gengrid_item_gengrid_get(const Elm_Gengrid_Item *item)
2844 {
2845    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
2846    return item->base.widget;
2847 }
2848
2849 /**
2850  * Show the given item
2851  *
2852  * This causes gengrid to jump to the given item @p item and show it
2853  * (by scrolling), if it is not fully visible.
2854  *
2855  * @param item The item
2856  *
2857  * @ingroup Gengrid
2858  */
2859 EAPI void
2860 elm_gengrid_item_show(Elm_Gengrid_Item *item)
2861 {
2862    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
2863    Widget_Data *wd = elm_widget_data_get(item->wd->self);
2864    Evas_Coord minx = 0, miny = 0;
2865
2866    if (!wd) return;
2867    if ((!item) || (item->delete_me)) return;
2868    _pan_min_get(wd->pan_smart, &minx, &miny);
2869
2870    elm_smart_scroller_child_region_show(item->wd->scr,
2871                                         item->x * wd->item_width + minx,
2872                                         item->y * wd->item_height + miny,
2873                                         item->wd->item_width,
2874                                         item->wd->item_height);
2875 }
2876
2877 /**
2878  * Bring in the given item
2879  *
2880  * This causes gengrig to jump to the given item @p item and show it
2881  * (by scrolling), if it is not fully visible. This may use animation
2882  * to do so and take a period of time
2883  *
2884  * @param item The item
2885  *
2886  * @ingroup Gengrid
2887  */
2888 EAPI void
2889 elm_gengrid_item_bring_in(Elm_Gengrid_Item *item)
2890 {
2891    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
2892    if (item->delete_me) return;
2893
2894    Evas_Coord minx = 0, miny = 0;
2895    Widget_Data *wd = elm_widget_data_get(item->wd->self);
2896    if (!wd) return;
2897    _pan_min_get(wd->pan_smart, &minx, &miny);
2898
2899    elm_smart_scroller_region_bring_in(item->wd->scr,
2900                                       item->x * wd->item_width + minx,
2901                                       item->y * wd->item_height + miny,
2902                                       item->wd->item_width,
2903                                       item->wd->item_height);
2904 }