1cfbe3200c95cdb21736741d105519460ee22907
[framework/uifw/elementary.git] / src / lib / elm_gengrid.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Gengrid Gengrid
6  * @ingroup Elementary
7  *
8  * This widget aims to position objects in a grid layout while actually
9  * building only the visible ones, using the same idea as genlist: the user
10  * define a class for each item, specifying functions that will be called at
11  * 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 parameter is
16  * the Gengrid item that was double-clicked.
17  *
18  * selected - The user has made an item selected. The event_info parameter is
19  * the Gengrid item that was selected.
20  *
21  * unselected - The user has made an item unselected. The event_info parameter
22  * is the Gengrid item that was unselected.
23  *
24  * realized - This is called when the item in the Gengrid is created as a real
25  * evas object. event_info is the Gengrid item that was created. The object may be
26  * deleted at any time, so it is up to the caller to not use the object pointer
27  * from elm_gengrid_item_object_get() in a way where it may point to
28  * freed objects.
29  *
30  * drag,start,up - Called when the item in the Gengrid has been dragged (not
31  * scrolled) up.
32  *
33  * drag,start,down - Called when the item in the Gengrid has been dragged (not
34  * scrolled) down.
35  *
36  * drag,start,left - Called when the item in the Gengrid has been dragged (not
37  * scrolled) left.
38  *
39  * drag,start,right - Called when the item in the Gengrid has been dragged (not
40  * scrolled) right.
41  *
42  * drag,stop - Called when the item in the Gengrid has stopped being dragged.
43  *
44  * drag - Called when the item in the Gengrid is being dragged.
45  *
46  * scroll - called when the content has been scrolled (moved).
47  *
48  * scroll,drag,start - called when dragging the content has started.
49  *
50  * scroll,drag,stop - called when dragging the content has stopped.
51  *
52  *
53  * A item in the Gengrid can have 0 or more text labels (they can be regular text
54  * or textblock - that's up to the style to determine), 0 or more icons (which
55  * are simply objects swallowed into the Gengrid item) and 0 or more boolean states
56  * that can be used for check, radio or other indicators by the edje theme style.
57  * A item may be one of several styles (Elementary provides 1 by default -
58  * "default", but this can be extended by system or application custom
59  * themes/overlays/extensions).
60  *
61  * In order to implement the ability to add and delete items on the fly, Gengrid
62  * implements a class/callback system where the application provides a structure
63  * with information about that type of item (Gengrid may contain multiple different
64  * items with different classes, states and styles). Gengrid will call the functions
65  * in this struct (methods) when an item is "realized" (that is created
66  * dynamically while scrolling). All objects will simply be deleted when no
67  * longer needed with evas_object_del(). The Elm_GenGrid_Item_Class structure
68  * contains the following members:
69  *
70  * item_style - This is a constant string and simply defines the name of the
71  * item style. It must be specified and the default should be "default".
72  *
73  * func.label_get - This function is called when an actual item object is
74  * created. The data parameter is the one passed to elm_gengrid_item_append()
75  * and related item creation functions. The obj parameter is the Gengrid object and
76  * the part parameter is the string name of the text part in the edje design that
77  * is listed as one of the possible labels that can be set. This function must
78  * return a strdup'()ed string as the caller will free() it when done.
79  *
80  * func.icon_get - This function is called when an actual item object is
81  * created. The data parameter is the one passed to elm_gengrid_item_append()
82  * and related item creation functions. The obj parameter is the Gengrid object and
83  * the part parameter is the string name of the icon part in the edje design that
84  * is listed as one of the possible icons that can be set. This must return NULL
85  * for no object or a valid object. The object will be deleted by Gengrid on
86  * shutdown or when the item is unrealized.
87  *
88  * func.state_get - This function is called when an actual item object is
89  * created. The data parameter is the one passed to elm_gengrid_item_append()
90  * and related item creation functions. The obj parameter is the Gengrid object and
91  * the part parameter is the string name of th state part in the edje design that
92  * is listed as one of the possible states that can be set. Return 0 for false
93  * and 1 for true. Gengrid will emit a signal to the edje object with
94  * "elm,state,XXX,active" "elm" when true (the default is false), where XXX is
95  * the name of the part.
96  *
97  * func.del - This is called when elm_gengrid_item_del() is called on a
98  * item or elm_gengrid_clear() is called on the Gengrid. This is intended for
99  * use when actual Gengrid items are deleted, so any backing data attached to the
100  * item (e.g. its data parameter on creation) can be deleted.
101  *
102  * If the application wants multiple items to be able to be selected,
103  * elm_gengrid_multi_select_set() can enable this. If the Gengrid is
104  * single-selection only (the default), then elm_gengrid_select_item_get()
105  * will return the selected item, if any, or NULL if none is selected. If the
106  * Gengrid is multi-select then elm_gengrid_selected_items_get() will return a
107  * list (that is only valid as long as no items are modified (added, deleted,
108  * selected or unselected).
109  *
110  * If a item changes (state of boolean changes, label or icons change), then use
111  * elm_gengrid_item_update() to have Gengrid update the item with the new
112  * state. Gengrid will re-realize the item thus call the functions in the
113  * _Elm_Gengrid_Item_Class for that item.
114  *
115  * To programmatically (un)select a item use elm_gengrid_item_selected_set().
116  * To get its selected state use elm_gengrid_item_selected_get(). To make a
117  * item disabled (unable to be selected and appear differently) use
118  * elm_gengrid_item_disable_set() to set this and
119  * elm_gengrid_item_disable_get() to get the disabled state.
120  *
121  * Cells will only call their selection func and callback when first becoming
122  * selected. Any further clicks will do nothing, unless you enable always
123  * select with elm_gengrid_always_select_mode_set(). This means event if
124  * selected, every click will make the selected callbacks be called.
125  * elm_gengrid_no_select_mode_set() will turn off the ability to select
126  * items entirely and they will neither appear selected nor call selected
127  * callback function.
128  *
129  * Remember that you can create new styles and add your own theme augmentation
130  * per application with elm_theme_extension_add(). If you absolutely must have a
131  * specific style that overrides any theme the user or system sets up you can use
132  * elm_theme_overlay_add() to add such a file.
133  *
134  * --
135  * TODO:
136  *  * Handle non-homogeneous objects too.
137  */
138
139 typedef struct _Widget_Data Widget_Data;
140 typedef struct _Pan Pan;
141
142 #define PRELOAD 1
143
144 struct _Elm_Gengrid_Item
145 {
146    Evas_Object *base, *spacer;
147    const Elm_Gengrid_Item_Class *gic;
148    Ecore_Timer *long_timer;
149    Widget_Data *wd;
150    Eina_List *labels, *icons, *states, *icon_objs;
151    const void *data;
152    struct
153      {
154         Evas_Smart_Cb func;
155         const void *data;
156      } func;
157
158    Evas_Coord x, y, dx, dy;
159    int relcount;
160
161    Eina_Bool want_unrealize : 1;
162    Eina_Bool realized : 1;
163    Eina_Bool dragging : 1;
164    Eina_Bool down : 1;
165    Eina_Bool delete_me : 1;
166    Eina_Bool display_only : 1;
167    Eina_Bool disabled : 1;
168    Eina_Bool selected : 1;
169    Eina_Bool hilighted : 1;
170    Eina_Bool walking : 1;
171 };
172
173 struct _Widget_Data
174 {
175    Evas_Object *self, *scr;
176    Evas_Object *pan_smart;
177    Pan *pan;
178    Eina_List *items;
179    Ecore_Job *calc_job;
180    Eina_List *selected;
181    double align_x, align_y;
182
183    Evas_Coord pan_x, pan_y;
184    Evas_Coord item_width, item_height;  /* Each item size */
185    Evas_Coord minw, minh;               /* Total obj size */
186    unsigned int nmax;
187
188    Eina_Bool horizontal : 1;
189    Eina_Bool on_hold : 1;
190    Eina_Bool longpressed : 1;
191    Eina_Bool multi : 1;
192    Eina_Bool no_select : 1;
193    Eina_Bool wasselected : 1;
194    Eina_Bool always_select : 1;
195 };
196
197 struct _Pan
198 {
199    Evas_Object_Smart_Clipped_Data __clipped_data;
200    Widget_Data *wd;
201 };
202
203 static const char *widtype = NULL;
204 static void _item_hilight(Elm_Gengrid_Item *item);
205 static void _item_unrealize(Elm_Gengrid_Item *item);
206 static void _item_select(Elm_Gengrid_Item *item);
207 static void _item_unselect(Elm_Gengrid_Item *item);
208 static void _calc_job(void *data);
209
210 static Evas_Smart_Class _pan_sc = EVAS_SMART_CLASS_INIT_VERSION;
211
212 static void
213 _theme_hook(Evas_Object *obj)
214 {
215    Widget_Data *wd = elm_widget_data_get(obj);
216    if (!wd) return;
217    elm_smart_scroller_object_theme_set(obj, wd->scr, "gengrid", "base",
218                                        elm_widget_style_get(obj));
219 }
220
221 static void
222 _del_hook(Evas_Object *obj)
223 {
224    Widget_Data *wd = elm_widget_data_get(obj);
225    if (!wd) return;
226    elm_gengrid_clear(obj);
227    evas_object_del(wd->pan_smart);
228    wd->pan_smart = NULL;
229    free(wd);
230 }
231
232 static void
233 _mouse_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj, void *event_info)
234 {
235    Elm_Gengrid_Item *item = data;
236    Evas_Event_Mouse_Move *ev = event_info;
237    Evas_Coord minw = 0, minh = 0, x, y, dx, dy, adx, ady;
238
239    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
240      {
241         if (!item->wd->on_hold) 
242           {
243              item->wd->on_hold = EINA_TRUE;
244              if (!item->wd->wasselected)
245                _item_unselect(item);
246           }
247      }
248    if ((item->dragging) && (item->down))
249      {
250         if (item->long_timer)
251           {
252              ecore_timer_del(item->long_timer);
253              item->long_timer = NULL;
254           }
255         evas_object_smart_callback_call(item->wd->self, "drag", item);
256         return;
257      }
258    if ((!item->down) || (item->wd->longpressed))
259      {
260         if (item->long_timer)
261           {
262              ecore_timer_del(item->long_timer);
263              item->long_timer = NULL;
264           }
265         return;
266      }
267    if (!item->display_only)
268      elm_coords_finger_size_adjust(1, &minw, 1, &minh);
269    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
270    x = ev->cur.canvas.x - x;
271    y = ev->cur.canvas.y - y;
272    dx = x - item->dx;
273    adx = dx;
274    if (adx < 0) adx = -dx;
275    dy = y - item->dy;
276    ady = dy;
277    if (ady < 0) ady = -dy;
278    minw /= 2;
279    minh /= 2;
280    if ((adx > minw) || (ady > minh))
281      {
282         item->dragging = 1;
283         if (item->long_timer)
284           {
285              ecore_timer_del(item->long_timer);
286              item->long_timer = NULL;
287           }
288         if (!item->wd->wasselected)
289           _item_unselect(item);
290         if (dy < 0)
291           {
292              if (ady > adx)
293                evas_object_smart_callback_call(item->wd->self, "drag,start,up",
294                                                item);
295              else
296                {
297                   if (dx < 0)
298                     evas_object_smart_callback_call(item->wd->self,
299                                                     "drag,start,left", item);
300                }
301           }
302         else
303           {
304              if (ady > adx)
305                evas_object_smart_callback_call(item->wd->self,
306                                                "drag,start,down", item);
307              else
308                {
309                   if (dx < 0)
310                     evas_object_smart_callback_call(item->wd->self,
311                                                     "drag,start,left", item);
312                   else
313                     evas_object_smart_callback_call(item->wd->self,
314                                                     "drag,start,right", item);
315                }
316           }
317      }
318 }
319
320 static Eina_Bool
321 _long_press(void *data)
322 {
323    Elm_Gengrid_Item *item = data;
324
325    item->long_timer = NULL;
326    if ((item->disabled) || (item->dragging)) return ECORE_CALLBACK_CANCEL;
327    item->wd->longpressed = EINA_TRUE;
328    evas_object_smart_callback_call(item->wd->self, "longpressed", item);
329    return ECORE_CALLBACK_CANCEL;
330 }
331
332 static void
333 _mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj, void *event_info)
334 {
335    Elm_Gengrid_Item *item = data;
336    Evas_Event_Mouse_Down *ev = event_info;
337    Evas_Coord x, y;
338
339    if (ev->button != 1) return;
340    item->down = 1;
341    item->dragging = 0;
342    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
343    item->dx = ev->canvas.x - x;
344    item->dy = ev->canvas.y - y;
345    item->wd->longpressed = EINA_FALSE;
346    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) item->wd->on_hold = EINA_TRUE;
347    else item->wd->on_hold = EINA_FALSE;
348    item->wd->wasselected = item->selected;
349    _item_hilight(item);
350    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
351      evas_object_smart_callback_call(item->wd->self, "clicked", item);
352    if (item->long_timer) ecore_timer_del(item->long_timer);
353    if (item->realized)
354      item->long_timer = ecore_timer_add(_elm_config->longpress_timeout, _long_press, item);
355    else
356      item->long_timer = NULL;
357 }
358
359 static void
360 _mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
361 {
362    Elm_Gengrid_Item *item = data;
363    Evas_Event_Mouse_Up *ev = event_info;
364    Eina_Bool dragged = EINA_FALSE;
365
366    if (ev->button != 1) return;
367    item->down = EINA_FALSE;
368    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) item->wd->on_hold = EINA_TRUE;
369    else item->wd->on_hold = EINA_FALSE;
370    if (item->long_timer)
371      {
372         ecore_timer_del(item->long_timer);
373         item->long_timer = NULL;
374      }
375    if (item->dragging)
376      {
377         item->dragging = EINA_FALSE;
378         evas_object_smart_callback_call(item->wd->self, "drag,stop", item);
379         dragged = EINA_TRUE;
380      }
381    if (item->wd->on_hold)
382      {
383         item->wd->longpressed = EINA_FALSE;
384         item->wd->on_hold = EINA_FALSE;
385         return;
386      }
387    if (item->wd->longpressed)
388      {
389         item->wd->longpressed = EINA_FALSE;
390         if (!item->wd->wasselected) _item_unselect(item);
391         item->wd->wasselected = EINA_FALSE;
392         return;
393      }
394    if (dragged)
395      {
396         if (item->want_unrealize) _item_unrealize(item);
397      }
398    if ((item->disabled) || dragged) return;
399    if (item->wd->multi)
400      {
401         if (!item->selected)
402           {
403              _item_hilight(item);
404              _item_select(item);
405           }
406         else _item_unselect(item);
407      }
408    else
409      {
410         if (!item->selected)
411           {
412              while (item->wd->selected) 
413                _item_unselect(item->wd->selected->data);
414           }
415         else
416           {
417              const Eina_List *l, *l_next;
418              Elm_Gengrid_Item *item2;
419
420              EINA_LIST_FOREACH_SAFE(item->wd->selected, l, l_next, item2)
421                if (item2 != item) _item_unselect(item2);
422           }
423         _item_hilight(item);
424         _item_select(item);
425      }
426 }
427
428 static void
429 _item_hilight(Elm_Gengrid_Item *item)
430 {
431    if ((item->wd->no_select) || (item->delete_me) || (item->hilighted)) return;
432    edje_object_signal_emit(item->base, "elm,state,selected", "elm");
433    item->hilighted = EINA_TRUE;
434 }
435
436 static void
437 _item_realize(Elm_Gengrid_Item *item)
438 {
439    char buf[1024];
440    char style[1024];
441
442    if ((item->realized) || (item->delete_me)) return;
443    item->base = edje_object_add(evas_object_evas_get(item->wd->self));
444    edje_object_scale_set(item->base, elm_widget_scale_get(item->wd->self) *
445                          _elm_config->scale);
446    evas_object_smart_member_add(item->base, item->wd->pan_smart);
447    elm_widget_sub_object_add(item->wd->self, item->base);
448    snprintf(style, sizeof(style), "item/%s",
449             item->gic->item_style ? item->gic->item_style : "default");
450    _elm_theme_object_set(item->wd->self, item->base, "gengrid", style,
451                          elm_widget_style_get(item->wd->self));
452    item->spacer = evas_object_rectangle_add(evas_object_evas_get(item->wd->self));
453    evas_object_color_set(item->spacer, 0, 0, 0, 0);
454    elm_widget_sub_object_add(item->wd->self, item->spacer);
455    evas_object_size_hint_min_set(item->spacer, 2 * _elm_config->scale, 1);
456    edje_object_part_swallow(item->base, "elm.swallow.pad", item->spacer);
457
458    if (item->gic->func.label_get)
459      {
460         const Eina_List *l;
461         const char *key;
462
463         item->labels = elm_widget_stringlist_get(edje_object_data_get(item->base,
464                                                                 "labels"));
465         EINA_LIST_FOREACH(item->labels, l, key)
466           {
467              char *s = item->gic->func.label_get(item->data, item->wd->self,
468                                                  l->data);
469              if (s)
470                {
471                   edje_object_part_text_set(item->base, l->data, s);
472                   free(s);
473                }
474           }
475      }
476
477    if (item->gic->func.icon_get)
478      {
479         const Eina_List *l;
480         const char *key;
481
482         item->icons = elm_widget_stringlist_get(edje_object_data_get(item->base,
483                                                                "icons"));
484         EINA_LIST_FOREACH(item->icons, l, key)
485           {
486              Evas_Object *ic = item->gic->func.icon_get(item->data,
487                                                         item->wd->self,
488                                                         l->data);
489              if (ic)
490                {
491                   item->icon_objs = eina_list_append(item->icon_objs, ic);
492                   edje_object_part_swallow(item->base, key, ic);
493                   evas_object_show(ic);
494                   elm_widget_sub_object_add(item->wd->self, ic);
495                }
496           }
497      }
498
499    if (item->gic->func.state_get)
500      {
501         const Eina_List *l;
502         const char *key;
503
504         item->states = elm_widget_stringlist_get(edje_object_data_get(item->base,
505                                                                 "states"));
506         EINA_LIST_FOREACH(item->states, l, key)
507           {
508              Eina_Bool on = item->gic->func.state_get(item->data,
509                                                       item->wd->self, l->data);
510              if (on)
511                {
512                   snprintf(buf, sizeof(buf), "elm,state,%s,active", key);
513                   edje_object_signal_emit(item->base, buf, "elm");
514                }
515           }
516      }
517
518    if ((!item->wd->item_width) && (!item->wd->item_height))
519      {
520         edje_object_size_min_restricted_calc(item->base,
521                                              &item->wd->item_width, &item->wd->item_height,
522                                              item->wd->item_width, item->wd->item_height);
523         elm_coords_finger_size_adjust(1, &item->wd->item_width,
524                                       1, &item->wd->item_height);
525      }
526
527    evas_object_event_callback_add(item->base, EVAS_CALLBACK_MOUSE_DOWN,
528                                   _mouse_down, item);
529    evas_object_event_callback_add(item->base, EVAS_CALLBACK_MOUSE_UP,
530                                   _mouse_up, item);
531    evas_object_event_callback_add(item->base, EVAS_CALLBACK_MOUSE_MOVE,
532                                   _mouse_move, item);
533
534    if (item->selected)
535      edje_object_signal_emit(item->base, "elm,state,selected", "elm");
536    if (item->disabled)
537      edje_object_signal_emit(item->base, "elm,state,disabled", "elm");
538
539    evas_object_show(item->base);
540    item->realized = EINA_TRUE;
541    item->want_unrealize = EINA_FALSE;
542 }
543
544 static void
545 _item_unrealize(Elm_Gengrid_Item *item)
546 {
547    Evas_Object *icon;
548
549    if (!item->realized) return;
550    if (item->long_timer)
551      {
552         ecore_timer_del(item->long_timer);
553         item->long_timer = NULL;
554      }
555    evas_object_del(item->base);
556    item->base = NULL;
557    evas_object_del(item->spacer);
558    item->spacer = NULL;
559    elm_widget_stringlist_free(item->labels);
560    item->labels = NULL;
561    elm_widget_stringlist_free(item->icons);
562    item->icons = NULL;
563    elm_widget_stringlist_free(item->states);
564
565    EINA_LIST_FREE(item->icon_objs, icon)
566      evas_object_del(icon);
567
568    item->states = NULL;
569    item->realized = EINA_FALSE;
570    item->want_unrealize = EINA_FALSE;
571 }
572
573 static void
574 _item_place(Elm_Gengrid_Item *item, Evas_Coord cx, Evas_Coord cy)
575 {
576    Evas_Coord x, y, ox, oy, cvx, cvy, cvw, cvh;
577    Evas_Coord tch, tcw, alignw = 0, alignh = 0, vw, vh;
578
579    item->x = cx;
580    item->y = cy;
581    evas_object_geometry_get(item->wd->pan_smart, &ox, &oy, &vw, &vh);
582    evas_output_viewport_get(evas_object_evas_get(item->wd->self),
583                             &cvx, &cvy, &cvw, &cvh);
584
585    /* Preload rows/columns at each side of the Gengrid */
586    cvx = ox - PRELOAD * item->wd->item_width;
587    cvy = oy - PRELOAD * item->wd->item_height;
588    cvw = vw + 2 * PRELOAD * item->wd->item_width;
589    cvh = vh + 2 * PRELOAD * item->wd->item_height;
590
591    tch = ((vh/item->wd->item_height)*item->wd->item_height);
592    alignh = (vh - tch)*item->wd->align_y;
593
594    tcw = ((vw/item->wd->item_width)*item->wd->item_width);
595    alignw = (vw - tcw)*item->wd->align_x;
596
597    if ((item->wd->horizontal) && (item->wd->minw < vw))
598      {
599         int columns;
600
601         columns = eina_list_count(item->wd->items)/(vh/item->wd->item_height);
602         if (eina_list_count(item->wd->items) % (vh/item->wd->item_height))
603           columns++;
604
605         tcw = item->wd->item_width * columns;
606         alignw = (vw - tcw)*item->wd->align_x;
607      }
608    else if ((item->wd->horizontal) && (item->wd->minw > vw))
609      alignw = 0;
610    if ((!item->wd->horizontal) && (item->wd->minh < vh))
611      {
612         int rows;
613
614         rows = eina_list_count(item->wd->items)/(vw/item->wd->item_width);
615         if (eina_list_count(item->wd->items) % (vw/item->wd->item_width))
616           rows++;
617
618         tch = item->wd->item_height * rows;
619         alignh = (vh - tch)*item->wd->align_y;
620      }
621    else if ((!item->wd->horizontal) && (item->wd->minh > vh))
622      alignh = 0;
623    x = cx * item->wd->item_width - item->wd->pan_x + ox + alignw;
624    y = cy * item->wd->item_height - item->wd->pan_y + oy + alignh;
625
626    if (ELM_RECTS_INTERSECT(x, y, item->wd->item_width, item->wd->item_height,
627                            cvx, cvy, cvw, cvh))
628      {
629         Eina_Bool was_realized = item->realized;
630
631         _item_realize(item);
632         if (!was_realized)
633           evas_object_smart_callback_call(item->wd->self, "realized", item);
634         evas_object_move(item->base, x, y);
635         evas_object_resize(item->base, item->wd->item_width,
636                            item->wd->item_height);
637      }
638    else
639      _item_unrealize(item);
640 }
641
642 static Elm_Gengrid_Item *
643 _item_create(Widget_Data *wd, const Elm_Gengrid_Item_Class *gic, const void *data, Evas_Smart_Cb func, const void *func_data)
644 {
645    Elm_Gengrid_Item *item;
646
647    item = calloc(1, sizeof(*item));
648    if (!item) return NULL;
649    item->wd = wd;
650    item->gic = gic;
651    item->data = data;
652    item->func.func = func;
653    item->func.data = func_data;
654    return item;
655 }
656
657 static void
658 _item_del(Elm_Gengrid_Item *item)
659 {
660    if (item->selected)
661      item->wd->selected = eina_list_remove(item->wd->selected, item);
662    if (item->realized) _item_unrealize(item);
663    if ((!item->delete_me) && (item->gic->func.del))
664      item->gic->func.del(item->data, item->wd->self);
665    item->delete_me = EINA_TRUE;
666    item->wd->items = eina_list_remove(item->wd->items, item);
667    if (item->long_timer) ecore_timer_del(item->long_timer);
668    if (item->wd->calc_job) ecore_job_del(item->wd->calc_job);
669    item->wd->calc_job = ecore_job_add(_calc_job, item->wd);
670    free(item);
671 }
672
673 static void
674 _item_select(Elm_Gengrid_Item *item)
675 {
676    if ((item->wd->no_select) || (item->delete_me)) return;
677    if (item->selected)
678      {
679         if (item->wd->always_select) goto call;
680         return;
681      }
682    item->selected = EINA_TRUE;
683    item->wd->selected = eina_list_append(item->wd->selected, item);
684 call:
685    item->walking++;
686    if (item->func.func) 
687      item->func.func((void *)item->func.data, item->wd->self, item);
688    if (!item->delete_me)
689      evas_object_smart_callback_call(item->wd->self, "selected", item);
690    item->walking--;
691    if ((item->walking == 0) && (item->delete_me))
692      if (item->relcount == 0) _item_del(item);
693 }
694
695 static void
696 _item_unselect(Elm_Gengrid_Item *item)
697 {
698    if ((item->delete_me) || (!item->hilighted)) return;
699    edje_object_signal_emit(item->base, "elm,state,unselected", "elm");
700    item->hilighted = EINA_FALSE;
701    if (item->selected)
702      {
703         item->selected = EINA_FALSE;
704         item->wd->selected = eina_list_remove(item->wd->selected, item);
705         evas_object_smart_callback_call(item->wd->self, "unselected", item);
706      }
707 }
708
709 static void
710 _calc_job(void *data)
711 {
712    Widget_Data *wd = data;
713    Evas_Coord minw = 0, minh = 0, nmax = 0, cvw, cvh;
714    int count;
715
716    evas_object_geometry_get(wd->pan_smart, NULL, NULL, &cvw, &cvh);
717    if ((wd->horizontal) && (wd->item_height))
718      nmax = cvh / wd->item_height;
719    else if (wd->item_width)
720      nmax = cvw / wd->item_width;
721
722    if (nmax)
723      {
724         count = eina_list_count(wd->items);
725         if (wd->horizontal)
726           {
727              minw = ceil(count  / (float)nmax) * wd->item_width;
728              minh = nmax * wd->item_height;
729           }
730         else
731           {
732              minw = nmax * wd->item_width;
733              minh = ceil(count / (float)nmax) * wd->item_height;
734           }
735      }
736
737    if ((minw != wd->minw) || (minh != wd->minh))
738      {
739         wd->minh = minh;
740         wd->minw = minw;
741         evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
742      }
743
744    wd->nmax = nmax;
745    wd->calc_job = NULL;
746    evas_object_smart_changed(wd->pan_smart);
747 }
748
749 static void
750 _pan_add(Evas_Object *obj)
751 {
752    Pan *sd;
753    Evas_Object_Smart_Clipped_Data *cd;
754
755    _pan_sc.add(obj);
756    cd = evas_object_smart_data_get(obj);
757    sd = ELM_NEW(Pan);
758    if (!sd) return;
759    sd->__clipped_data = *cd;
760    free(cd);
761    evas_object_smart_data_set(obj, sd);
762 }
763
764 static void
765 _pan_del(Evas_Object *obj)
766 {
767    Pan *sd = evas_object_smart_data_get(obj);
768
769    if (!sd) return;
770    _pan_sc.del(obj);
771 }
772
773 static void
774 _pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
775 {
776    Pan *sd = evas_object_smart_data_get(obj);
777    if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return;
778    sd->wd->pan_x = x;
779    sd->wd->pan_y = y;
780    evas_object_smart_changed(obj);
781 }
782
783 static void
784 _pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
785 {
786    Pan *sd = evas_object_smart_data_get(obj);
787    if (x) *x = sd->wd->pan_x;
788    if (y) *y = sd->wd->pan_y;
789 }
790
791 static void
792 _pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
793 {
794    Pan *sd = evas_object_smart_data_get(obj);
795    if (w) *w = sd->wd->minw;
796    if (h) *h = sd->wd->minh;
797 }
798
799 static void
800 _pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
801 {
802    Pan *sd = evas_object_smart_data_get(obj);
803    Evas_Coord ow, oh;
804
805    if (!sd) return;
806    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
807    if (x)
808      *x = (ow < sd->wd->minw) ? sd->wd->minw - ow : 0;
809    if (y)
810      *y = (oh < sd->wd->minh) ? sd->wd->minh - oh : 0;
811 }
812
813 static void
814 _pan_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
815 {
816    Pan *sd = evas_object_smart_data_get(obj);
817    Evas_Coord ow, oh;
818
819    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
820    if ((ow == w) && (oh == h)) return;
821    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
822    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
823 }
824
825 static void
826 _pan_calculate(Evas_Object *obj)
827 {
828    Pan *sd = evas_object_smart_data_get(obj);
829    Evas_Coord cx = 0, cy = 0;
830    Eina_List *l;
831    Elm_Gengrid_Item *item;
832
833    if (!sd) return;
834    if (!sd->wd->nmax) return;
835
836    EINA_LIST_FOREACH(sd->wd->items, l, item)
837      {
838         _item_place(item, cx, cy);
839         if (sd->wd->horizontal)
840           {
841              cy = (cy + 1) % sd->wd->nmax;
842              if (!cy) cx++;
843           }
844         else
845           {
846              cx = (cx + 1) % sd->wd->nmax;
847              if (!cx) cy++;
848           }
849      }
850 }
851
852 static void
853 _pan_move(Evas_Object *obj, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
854 {
855    Pan *sd = evas_object_smart_data_get(obj);
856    if (!sd) return;
857    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
858    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
859 }
860
861 static void
862 _hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
863 {
864    Widget_Data *wd = elm_widget_data_get(obj);
865    if (!wd) return;
866    elm_smart_scroller_hold_set(wd->scr, 1);
867 }
868
869 static void
870 _hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
871 {
872    Widget_Data *wd = elm_widget_data_get(obj);
873    if (!wd) return;
874    elm_smart_scroller_hold_set(wd->scr, 0);
875 }
876
877 static void
878 _freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
879 {
880    Widget_Data *wd = elm_widget_data_get(obj);
881    if (!wd) return;
882    elm_smart_scroller_freeze_set(wd->scr, 1);
883 }
884
885 static void
886 _freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
887 {
888    Widget_Data *wd = elm_widget_data_get(obj);
889    if (!wd) return;
890    elm_smart_scroller_freeze_set(wd->scr, 0);
891 }
892
893 static void
894 _scr_drag_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
895 {
896    evas_object_smart_callback_call(data, "scroll,drag,start", NULL);
897 }
898
899 static void
900 _scr_drag_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
901 {
902    evas_object_smart_callback_call(data, "scroll,drag,stop", NULL);
903 }
904
905 static void
906 _scr_scroll(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
907 {
908    evas_object_smart_callback_call(data, "scroll", NULL);
909 }
910
911 /**
912  * Add a new Gengrid object.
913  *
914  * @param parent The parent object.
915  * @return  The new object or NULL if it cannot be created.
916  *
917  * @see elm_gengrid_item_size_set()
918  * @see elm_gengrid_horizontal_set()
919  * @see elm_gengrid_item_append()
920  * @see elm_gengrid_item_del()
921  * @see elm_gengrid_clear()
922  *
923  * @ingroup Gengrid
924  */
925 EAPI Evas_Object *
926 elm_gengrid_add(Evas_Object *parent)
927 {
928    if (!parent) return NULL;
929    
930    Evas_Object *obj;
931    Evas *e;
932    Widget_Data *wd;
933    static Evas_Smart *smart = NULL;
934
935    wd = ELM_NEW(Widget_Data);
936    e = evas_object_evas_get(parent);
937    obj = elm_widget_add(e);
938    ELM_SET_WIDTYPE(widtype, "gengrid");
939    elm_widget_type_set(obj, "gengrid");
940    elm_widget_sub_object_add(parent, obj);
941    elm_widget_data_set(obj, wd);
942    elm_widget_del_hook_set(obj, _del_hook);
943    elm_widget_theme_hook_set(obj, _theme_hook);
944
945    wd->scr = elm_smart_scroller_add(e);
946    elm_smart_scroller_widget_set(wd->scr, obj);
947    elm_smart_scroller_object_theme_set(obj, wd->scr, "gengrid", "base", "default");
948    elm_widget_resize_object_set(obj, wd->scr);
949
950    evas_object_smart_callback_add(wd->scr, "drag,start", _scr_drag_start, obj);
951    evas_object_smart_callback_add(wd->scr, "drag,stop", _scr_drag_stop, obj);
952    evas_object_smart_callback_add(wd->scr, "scroll", _scr_scroll, obj);
953
954    elm_smart_scroller_bounce_allow_set(wd->scr, 1, 1);
955
956    wd->self = obj;
957    wd->align_x = 0.5;
958    wd->align_y = 0.5;
959
960    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
961    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
962    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
963    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
964
965    if (!smart)
966      {
967         static Evas_Smart_Class sc;
968
969         evas_object_smart_clipped_smart_set(&_pan_sc);
970         sc = _pan_sc;
971         sc.name = "elm_gengrid_pan";
972         sc.version = EVAS_SMART_CLASS_VERSION;
973         sc.add = _pan_add;
974         sc.del = _pan_del;
975         sc.resize = _pan_resize;
976         sc.move = _pan_move;
977         sc.calculate = _pan_calculate;
978         smart = evas_smart_class_new(&sc);
979      }
980    if (smart)
981      {
982         wd->pan_smart = evas_object_smart_add(e, smart);
983         wd->pan = evas_object_smart_data_get(wd->pan_smart);
984         wd->pan->wd = wd;
985      }
986
987    elm_smart_scroller_extern_pan_set(wd->scr, wd->pan_smart,
988                                      _pan_set, _pan_get,
989                                      _pan_max_get, _pan_child_size_get);
990
991    return obj;
992 }
993
994 /**
995  * Set the size for the item of the Gengrid.
996  *
997  * @param obj The Gengrid object.
998  * @param w The item's width.
999  * @param h The item's height;
1000  *
1001  * @see elm_gengrid_item_size_get()
1002  *
1003  * @ingroup Gengrid
1004  */
1005 EAPI void
1006 elm_gengrid_item_size_set(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
1007 {
1008    ELM_CHECK_WIDTYPE(obj, widtype);
1009    Widget_Data *wd = elm_widget_data_get(obj);
1010    if (!wd) return;
1011    if ((wd->item_width == w) && (wd->item_height == h)) return;
1012    wd->item_width = w;
1013    wd->item_height = h;
1014    if (wd->calc_job) ecore_job_del(wd->calc_job);
1015    wd->calc_job = ecore_job_add(_calc_job, wd);
1016 }
1017
1018 /**
1019  * Get the size of the item of the Gengrid.
1020  *
1021  * @param obj The Gengrid object.
1022  * @param w Pointer to the item's width.
1023  * @param h Pointer to the item's height.
1024  *
1025  * @see elm_gengrid_item_size_get()
1026  *
1027  * @ingroup Gengrid
1028  */
1029 EAPI void
1030 elm_gengrid_item_size_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
1031 {
1032    ELM_CHECK_WIDTYPE(obj, widtype);
1033    Widget_Data *wd = elm_widget_data_get(obj);
1034    if (!wd) return;
1035    if (w) *w = wd->item_width;
1036    if (h) *h = wd->item_height;
1037 }
1038
1039 /**
1040  * Set item's alignment within the scroller.
1041  *
1042  * @param obj The Gengrid object.
1043  * @param align_x The x alignment (0 <= x <= 1).
1044  * @param align_y The y alignment (0 <= y <= 1).
1045  *
1046  * @see elm_gengrid_align_get()
1047  *
1048  * @ingroup Gengrid
1049  */
1050 EAPI void
1051 elm_gengrid_align_set(Evas_Object *obj, double align_x, double align_y)
1052 {
1053    ELM_CHECK_WIDTYPE(obj, widtype);
1054    Widget_Data *wd = elm_widget_data_get(obj);
1055
1056    if (align_x > 1.0)
1057      align_x = 1.0;
1058    else if (align_x < 0.0)
1059      align_x = 0.0;
1060    wd->align_x = align_x;
1061
1062    if (align_y > 1.0)
1063      align_y = 1.0;
1064    else if (align_y < 0.0)
1065      align_y = 0.0;
1066    wd->align_y = align_y;
1067 }
1068
1069 /**
1070  * Get the alignenment set for the Gengrid object.
1071  *
1072  * @param obj The Gengrid object.
1073  * @param align_x Pointer to x alignenment.
1074  * @param align_y Pointer to y alignenment.
1075  *
1076  * @see elm_gengrid_align_set()
1077  *
1078  * @ingroup Gengrid
1079  */
1080 EAPI void
1081 elm_gengrid_align_get(const Evas_Object *obj, double *align_x, double *align_y)
1082 {
1083     ELM_CHECK_WIDTYPE(obj, widtype);
1084     Widget_Data *wd = elm_widget_data_get(obj);
1085     if (!wd) return;
1086     if (align_x) *align_x = wd->align_x;
1087     if (align_y) *align_y = wd->align_y;
1088 }
1089
1090 /**
1091  * Add item to the end of the Gengrid.
1092  *
1093  * @param obj The Gengrid object.
1094  * @param gic The item class for the item.
1095  * @param data The item data.
1096  * @param func Convenience function called when item is selected.
1097  * @param func_data Data passed to @p func above.
1098  * @return A handle to the item added or NULL if not possible.
1099  *
1100  * @see elm_gengrid_item_del()
1101  *
1102  * @ingroup Gengrid
1103  */
1104 EAPI Elm_Gengrid_Item *
1105 elm_gengrid_item_append(Evas_Object *obj, const Elm_Gengrid_Item_Class *gic,
1106                            const void *data, Evas_Smart_Cb func,
1107                            const void *func_data)
1108 {
1109    Elm_Gengrid_Item *item;
1110    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1111    Widget_Data *wd = elm_widget_data_get(obj);
1112    if (!wd) return NULL;
1113
1114    item = _item_create(wd, gic, data, func, func_data);
1115    if (!item) return NULL;
1116
1117    wd->items = eina_list_append(wd->items, item);
1118    wd->no_select = EINA_FALSE;
1119
1120    if (wd->calc_job) ecore_job_del(wd->calc_job);
1121    wd->calc_job = ecore_job_add(_calc_job, wd);
1122
1123    return item;
1124 }
1125
1126 /**
1127  * Prepend item at start of the Gengrid
1128  *
1129  * This adds an item to the beginning of the list or beginning of the children
1130  * of the parent if given.
1131  *
1132  * @param obj The Gengrid object.
1133  * @param gic The item class for the item.
1134  * @param data The item data.
1135  * @param func Convenience function called when item is selected.
1136  * @param func_data Data passed to @p func above.
1137  * @return A handle to the item added or NULL if not possible.
1138  *
1139  * @see elm_gengrid_item_del()
1140  *
1141  * @ingroup Gengrid
1142  */
1143
1144
1145 EAPI Elm_Gengrid_Item *
1146 elm_gengrid_item_prepend(Evas_Object *obj, const Elm_Gengrid_Item_Class *gic,
1147                             const void *data, Evas_Smart_Cb func,
1148                             const void *func_data)
1149 {
1150    Elm_Gengrid_Item *item;
1151    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1152    Widget_Data *wd = elm_widget_data_get(obj);
1153    if (!wd) return NULL;
1154    
1155    item = _item_create(wd, gic, data, func, func_data);
1156    if (!item) return NULL;
1157    
1158    wd->items = eina_list_prepend(wd->items, item);
1159    wd->no_select = EINA_FALSE;
1160    
1161    if (wd->calc_job) ecore_job_del(wd->calc_job);
1162    wd->calc_job = ecore_job_add(_calc_job, wd);
1163    
1164    return item;
1165 }
1166
1167 /**
1168  * Remove a item from the Gengrid.
1169  *
1170  * @param item The item to be removed.
1171  * @return @c EINA_TRUE on success or @c EINA_FALSE otherwise.
1172  *
1173  * @see elm_gengrid_clear() to remove all items of the Gengrid.
1174  *
1175  * @ingroup Gengrid
1176  */
1177 EAPI void
1178 elm_gengrid_item_del(Elm_Gengrid_Item *item)
1179 {
1180    if (!item) return;
1181    if ((item->relcount > 0) || (item->walking > 0))
1182      {
1183         item->delete_me = EINA_TRUE;
1184         if (item->selected)
1185           item->wd->selected = eina_list_remove(item->wd->selected, item);
1186         if (item->gic->func.del) 
1187           item->gic->func.del(item->data, item->wd->self);
1188         return;
1189      }
1190
1191    _item_del(item);
1192 }
1193
1194 /**
1195  * Set for what direction the Gengrid will expand.
1196  *
1197  * @param obj The Gengrid object.
1198  * @param setting If @c EINA_TRUE the Gengrid will expand horizontally or
1199  * vertically if @c EINA_FALSE.
1200  *
1201  * @ingroup Gengrid
1202  */
1203 EAPI void
1204 elm_gengrid_horizontal_set(Evas_Object *obj, Eina_Bool setting)
1205 {
1206    ELM_CHECK_WIDTYPE(obj, widtype);
1207    Widget_Data *wd = elm_widget_data_get(obj);
1208    if (!wd) return;
1209    if (setting == wd->horizontal) return;
1210    wd->horizontal = setting;
1211
1212    /* Update the items to conform to the new layout */
1213    if (wd->calc_job) ecore_job_del(wd->calc_job);
1214    wd->calc_job = ecore_job_add(_calc_job, wd);
1215 }
1216
1217 /**
1218  * Clear the Gengrid
1219  *
1220  * This clears all items in the Gengrid, leaving it empty.
1221  *
1222  * @param obj The Gengrid object.
1223  *
1224  * @see elm_gengrid_item_del() to remove just one item.
1225  *
1226  * @ingroup Gengrid
1227  */
1228 EAPI void
1229 elm_gengrid_clear(Evas_Object *obj)
1230 {
1231    Eina_List *l, *l_next;
1232    Elm_Gengrid_Item *item;
1233    ELM_CHECK_WIDTYPE(obj, widtype);
1234    Widget_Data *wd = elm_widget_data_get(obj);
1235    if (!wd) return;
1236
1237    if (wd->calc_job)
1238      {
1239         ecore_job_del(wd->calc_job);
1240         wd->calc_job = NULL;
1241      }
1242
1243    EINA_LIST_FOREACH_SAFE(wd->items, l, l_next, item)
1244      {
1245         if (item->realized) _item_unrealize(item);
1246         if (item->gic->func.del) item->gic->func.del(item->data, wd->self);
1247         if (item->long_timer) ecore_timer_del(item->long_timer);
1248         free(item);
1249         wd->items = eina_list_remove_list(wd->items, l);
1250      }
1251
1252    if (wd->selected)
1253      {
1254         eina_list_free(wd->selected);
1255         wd->selected = NULL;
1256      }
1257
1258    wd->pan_x = 0;
1259    wd->pan_y = 0;
1260    wd->minw = 0;
1261    wd->minh = 0;
1262    evas_object_size_hint_min_set(wd->pan_smart, wd->minw, wd->minh);
1263    evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
1264 }
1265
1266 /**
1267  * Get the real evas object of the Gengrid item
1268  *
1269  * This returns the actual evas object used for the specified Gengrid item.
1270  * This may be NULL as it may not be created, and may be deleted at any time
1271  * by Gengrid. Do not modify this object (move, resize, show, hide etc.) as
1272  * Gengrid is controlling it. This function is for querying, emitting custom
1273  * signals or hooking lower level callbacks for events. Do not delete this
1274  * object under any circumstances.
1275  *
1276  * @param item The Gengrid item.
1277  * @return the evas object associated to this item.
1278  *
1279  * @see elm_gengrid_item_data_get()
1280  *
1281  * @ingroup Gengrid
1282  */
1283 EAPI const Evas_Object *
1284 elm_gengrid_item_object_get(Elm_Gengrid_Item *item)
1285 {
1286    if (!item) return NULL;
1287    return item->base;
1288 }
1289
1290 /**
1291  * Returns the data associated to a item
1292  *
1293  * This returns the data value passed on the elm_gengrid_item_append() and
1294  * related item addition calls.
1295  *
1296  * @param item The Gengrid item.
1297  * @return the data associated to this item.
1298  *
1299  * @see elm_gengrid_item_append()
1300  * @see elm_gengrid_item_object_get()
1301  *
1302  * @ingroup Gengrid
1303  */
1304 EAPI void *
1305 elm_gengrid_item_data_get(Elm_Gengrid_Item *item)
1306 {
1307    if (!item) return NULL;
1308    return (void *)item->data;
1309 }
1310
1311 /**
1312  * Get the item's coordinates.
1313  *
1314  * This returns the logical position of the item whithin the Gengrid.
1315  *
1316  * @param item The Gengrid item.
1317  * @param x The x-axis coordinate pointer.
1318  * @param y The y-axis coordinate pointer.
1319  *
1320  * @ingroup Gengrid
1321  */
1322 EAPI void
1323 elm_gengrid_item_pos_get(const Elm_Gengrid_Item *item, unsigned int *x, unsigned int *y)
1324 {
1325    if (!item) return;
1326    if (x) *x = item->x;
1327    if (y) *y = item->y;
1328 }
1329
1330 /**
1331  * Enable or disable multi-select in the Gengrid.
1332  *
1333  * This enables (EINA_TRUE) or disables (EINA_FALSE) multi-select in the Gengrid.
1334  * This allows more than 1 item to be selected.
1335  *
1336  * @param obj The Gengrid object.
1337  * @param multi Multi-select enabled/disabled
1338  *
1339  * @ingroup Gengrid
1340  */
1341 EAPI void
1342 elm_gengrid_multi_select_set(Evas_Object *obj, Eina_Bool multi)
1343 {
1344    ELM_CHECK_WIDTYPE(obj, widtype);
1345    Widget_Data *wd = elm_widget_data_get(obj);
1346    if (!wd) return;
1347    wd->multi = multi;
1348 }
1349
1350 /**
1351  * Get if multi-select in Gengrid is enabled or disabled
1352  *
1353  * @param obj The Gengrid object
1354  * @return Multi-select enable/disable
1355  * (EINA_TRUE = enabled / EINA_FALSE = disabled)
1356  *
1357  * @ingroup Gengrid
1358  */
1359 EAPI Eina_Bool
1360 elm_gengrid_multi_select_get(const Evas_Object *obj)
1361 {
1362    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1363    Widget_Data *wd = elm_widget_data_get(obj);
1364    if (!wd) return EINA_FALSE;
1365    return wd->multi;
1366 }
1367
1368 /**
1369  * Get the selected item in the Gengrid
1370  *
1371  * This gets the selected item in the Gengrid (if multi-select is enabled only
1372  * the first item in the list is selected - which is not very useful, so see
1373  * elm_gengrid_selected_items_get() for when multi-select is used).
1374  *
1375  * If no item is selected, NULL is returned.
1376  *
1377  * @param obj The Gengrid object.
1378  * @return The selected item, or NULL if none.
1379  *
1380  * @ingroup Gengrid
1381  */
1382 EAPI Elm_Gengrid_Item *
1383 elm_gengrid_selected_item_get(const Evas_Object *obj)
1384 {
1385    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1386    Widget_Data *wd = elm_widget_data_get(obj);
1387    if (!wd) return NULL;
1388    if (wd->selected) return wd->selected->data;
1389    return NULL;
1390 }
1391
1392 /**
1393  * Get a list of selected items in the Gengrid.
1394  *
1395  * This returns a list of the selected items. This list pointer is only valid
1396  * so long as no items are selected or unselected (or unselected implictly by
1397  * deletion). The list contains Elm_Gengrid_Item pointers.
1398  *
1399  * @param obj The Gengrid object.
1400  * @return The list of selected items, or NULL if none are selected.
1401  *
1402  * @ingroup Gengrid
1403  */
1404 EAPI const Eina_List *
1405 elm_gengrid_selected_items_get(const Evas_Object *obj)
1406 {
1407    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1408    Widget_Data *wd = elm_widget_data_get(obj);
1409    if (!wd) return NULL;
1410    return wd->selected;
1411 }
1412
1413 /**
1414  * Set the selected state of a item.
1415  *
1416  * This sets the selected state of a item. If multi-select is not enabled and
1417  * selected is EINA_TRUE, previously selected items are unselected.
1418  *
1419  * @param item The item
1420  * @param selected The selected state.
1421  *
1422  * @ingroup Gengrid
1423  */
1424 EAPI void
1425 elm_gengrid_item_selected_set(Elm_Gengrid_Item *item, Eina_Bool selected)
1426 {
1427    Widget_Data *wd = elm_widget_data_get(item->wd->self);
1428    if (!wd) return;
1429    if ((!item) || (item->delete_me)) return;
1430    selected = !!selected;
1431    if (item->selected == selected) return;
1432
1433    if (selected)
1434      {
1435         if (!wd->multi)
1436           {
1437              while (wd->selected)
1438                _item_unselect(wd->selected->data);
1439           }
1440         _item_hilight(item);
1441         _item_select(item);
1442      }
1443    else
1444      _item_unselect(item);
1445 }
1446
1447 /**
1448  * Get the selected state of a item.
1449  *
1450  * This gets the selected state of a item (1 selected, 0 not selected).
1451  *
1452  * @param item The item
1453  * @return The selected state
1454  *
1455  * @ingroup Gengrid
1456  */
1457 EAPI Eina_Bool
1458 elm_gengrid_item_selected_get(const Elm_Gengrid_Item *item)
1459 {
1460    if (!item) return EINA_FALSE;
1461    return item->selected;
1462 }
1463
1464 /**
1465  * Sets the disabled state of a item.
1466  *
1467  * A disabled item cannot be selected or unselected. It will also change
1468  * appearance to disabled. This sets the disabled state (1 disabled, 0 not
1469  * disabled).
1470  *
1471  * @param item The item
1472  * @param disabled The disabled state
1473  *
1474  * @ingroup Gengrid
1475  */
1476 EAPI void
1477 elm_gengrid_item_disabled_set(Elm_Gengrid_Item *item, Eina_Bool disabled)
1478 {
1479    if (!item) return;
1480    if (item->disabled == disabled) return;
1481    if (item->delete_me) return;
1482    item->disabled = disabled;
1483    if (item->realized)
1484      {
1485         if (item->disabled)
1486           edje_object_signal_emit(item->base, "elm,state,disabled", "elm");
1487         else
1488           edje_object_signal_emit(item->base, "elm,state,enabled", "elm");
1489      }
1490 }
1491
1492 /**
1493  * Get the disabled state of a item.
1494  *
1495  * This gets the disabled state of the given item.
1496  *
1497  * @param item The item
1498  * @return The disabled state
1499  *
1500  * @ingroup Gengrid
1501  */
1502 EAPI Eina_Bool
1503 elm_gengrid_item_disabled_get(const Elm_Gengrid_Item *item)
1504 {
1505    if (!item) return EINA_FALSE;
1506    if (item->delete_me) return EINA_FALSE;
1507    return item->disabled;
1508 }
1509
1510 /**
1511  * Set the always select mode.
1512  *
1513  * Cells will only call their selection func and callback when first becoming
1514  * selected. Any further clicks will do nothing, unless you enable always select
1515  * with elm_gengrid_always_select_mode_set(). This means even if selected,
1516  * every click will make the selected callbacks be called.
1517  *
1518  * @param obj The Gengrid object
1519  * @param always_select The always select mode (EINA_TRUE = on, EINA_FALSE = off)
1520  *
1521  * @ingroup Gengrid
1522  */
1523 EAPI void
1524 elm_gengrid_always_select_mode_set(Evas_Object *obj, Eina_Bool always_select)
1525 {
1526    ELM_CHECK_WIDTYPE(obj, widtype);
1527    Widget_Data *wd = elm_widget_data_get(obj);
1528    if (!wd) return;
1529    wd->always_select = always_select;
1530 }
1531
1532 /**
1533  * Get the always select mode.
1534  *
1535  * @param obj The Gengrid object.
1536  * @return The always select mode (EINA_TRUE = on, EINA_FALSE = off)
1537  *
1538  * @ingroup Gengrid
1539  */
1540 EAPI Eina_Bool
1541 elm_gengrid_always_select_mode_get(const Evas_Object *obj)
1542 {
1543    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1544    Widget_Data *wd = elm_widget_data_get(obj);
1545    if (!wd) return EINA_FALSE;
1546    return wd->always_select;
1547 }
1548
1549 /**
1550  * Set no select mode.
1551  *
1552  * This will turn off the ability to select items entirely and they will
1553  * neither appear selected nor call selected callback functions.
1554  *
1555  * @param obj The Gengrid object
1556  * @param no_select The no select mode (EINA_TRUE = on, EINA_FALSE = off)
1557  *
1558  * @ingroup Gengrid
1559  */
1560 EAPI void
1561 elm_gengrid_no_select_mode_set(Evas_Object *obj, Eina_Bool no_select)
1562 {
1563    ELM_CHECK_WIDTYPE(obj, widtype);
1564    Widget_Data *wd = elm_widget_data_get(obj);
1565    if (!wd) return;
1566    wd->no_select = no_select;
1567 }
1568
1569 /**
1570  * Gets no select mode.
1571  *
1572  * @param obj The Gengrid object
1573  * @return The no select mode (EINA_TRUE = on, EINA_FALSE = off)
1574  *
1575  * @ingroup Gengrid
1576  */
1577 EAPI Eina_Bool
1578 elm_gengrid_no_select_mode_get(const Evas_Object *obj)
1579 {
1580    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1581    Widget_Data *wd = elm_widget_data_get(obj);
1582    if (!wd) return EINA_FALSE;
1583    return wd->no_select;
1584 }
1585
1586 /**
1587  * Set bounce mode.
1588  *
1589  * This will enable or disable the scroller bounce mode for the Gengrid. See
1590  * elm_scroller_bounce_set() for details.
1591  *
1592  * @param obj The Gengrid object
1593  * @param h_bounce Allow bounce horizontally
1594  * @param v_bounce Allow bounce vertically
1595  *
1596  * @ingroup Gengrid
1597  */
1598 EAPI void
1599 elm_gengrid_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce)
1600 {
1601    ELM_CHECK_WIDTYPE(obj, widtype);
1602    Widget_Data *wd = elm_widget_data_get(obj);
1603    if (!wd) return;
1604    elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
1605 }
1606
1607 /**
1608  * Get the bounce mode
1609  *
1610  * @param obj The Gengrid object
1611  * @param h_bounce Allow bounce horizontally
1612  * @param v_bounce Allow bounce vertically
1613  *
1614  * @ingroup Gengrid
1615  */
1616 EAPI void
1617 elm_gengrid_bounce_get(const Evas_Object *obj, Eina_Bool *h_bounce, Eina_Bool *v_bounce)
1618 {
1619    ELM_CHECK_WIDTYPE(obj, widtype);
1620    Widget_Data *wd = elm_widget_data_get(obj);
1621    if (!wd) return;
1622    elm_smart_scroller_bounce_allow_get(wd->scr, h_bounce, v_bounce);
1623 }
1624
1625 /**
1626  * Get all items in the Gengrid.
1627  *
1628  * This returns a list of the Gengrid items. The list contains
1629  * Elm_Gengrid_Item pointers.
1630  *
1631  * @param obj The Gengrid object.
1632  * @return The list of items, or NULL if none.
1633  *
1634  * @ingroup Gengrid
1635  */
1636 EAPI const Eina_List *
1637 elm_gengrid_items_get(const Evas_Object *obj)
1638 {
1639    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1640    Widget_Data *wd = elm_widget_data_get(obj);
1641    if (!wd) return NULL;
1642    return wd->items;
1643 }
1644
1645 /**
1646  * Update the contents of an item
1647  * 
1648  * This updates an item by calling all the item class functions again to get
1649  * the icons, labels and states. Use this when he original item data has
1650  * changed and the changes are desired to be reflected.
1651  * 
1652  * @param it The item
1653  * 
1654  * @ingroup Gengrid
1655  */
1656 EAPI void
1657 elm_gengrid_item_update(Elm_Gengrid_Item *item)
1658 {
1659    if (item->realized)
1660    {
1661       _item_unrealize(item);
1662       _item_realize(item);
1663       evas_object_smart_callback_call(item->wd->self, "realized", item);
1664
1665       if (item->wd->calc_job) ecore_job_del(item->wd->calc_job);
1666          item->wd->calc_job = ecore_job_add(_calc_job, item->wd);
1667    }
1668 }
1669