more work on genlist!
authorCarsten Haitzler <raster@rasterman.com>
Thu, 12 Feb 2009 13:39:43 +0000 (13:39 +0000)
committerCarsten Haitzler <raster@rasterman.com>
Thu, 12 Feb 2009 13:39:43 +0000 (13:39 +0000)
SVN revision: 39002

data/themes/default.edc
src/bin/test.c
src/lib/Elementary.h.in
src/lib/elm_genlist.c

index 751c3ec..7f8d284 100644 (file)
@@ -7021,4 +7021,419 @@ collections {
       }
    }
 
+///////////////////////////////////////////////////////////////////////////////
+   group { name: "elm/genlist/item/default/default";
+      data.item: "stacking" "above";
+      data.item: "selectraise" "on";
+      data.item: "labels" "elm.text";
+      data.item: "icons" "elm.swallow.icon elm.swallow.end";
+//      data.item: "states" "";
+      images {
+         image: "bt_sm_base1.png" COMP;
+         image: "bt_sm_shine.png" COMP;
+         image: "bt_sm_hilight.png" COMP;
+         image: "ilist_1.png" COMP;
+         image: "ilist_item_shadow.png" COMP;
+      }
+      parts {
+         part {
+            name: "base_sh";
+            mouse_events: 0;
+            description {
+               state: "default" 0.0;
+               align: 0.0 0.0;
+               min: 0 10;
+               fixed: 1 1;
+               rel1 {
+                  to: "base";
+                  relative: 0.0 1.0;
+                  offset: 0 0;
+               }
+               rel2 {
+                  to: "base";
+                  relative: 1.0 1.0;
+                  offset: -1 0;
+               }
+               image {
+                  normal: "ilist_item_shadow.png";
+               }
+               fill.smooth: 0;
+            }
+         }
+         part {
+            name: "base";
+            mouse_events: 0;
+            description {
+               state: "default" 0.0;
+               image {
+                  normal: "ilist_1.png";
+                  border: 2 2 2 2;
+               }
+               fill.smooth: 0;
+            }
+         }
+         part { name: "bg";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               visible: 0;
+               color: 255 255 255 0;
+               rel1 {
+                  relative: 0.0 0.0;
+                  offset: -5 -5;
+               }
+               rel2 {
+                  relative: 1.0 1.0;
+                  offset: 4 4;
+               }
+               image {
+                  normal: "bt_sm_base1.png";
+                  border: 6 6 6 6;
+               }
+            }
+            description { state: "selected" 0.0;
+               inherit: "default" 0.0;
+               visible: 1;
+               color: 255 255 255 255;
+               rel1 {
+                  relative: 0.0 0.0;
+                  offset: -2 -2;
+               }
+               rel2 {
+                  relative: 1.0 1.0;
+                  offset: 1 1;
+               }
+            }
+         }
+         part { name: "elm.swallow.icon";
+            type: SWALLOW;
+            description { state: "default" 0.0;
+               fixed: 1 0;
+               align: 0.0 0.5;
+               rel1 {
+                  relative: 0.0  0.0;
+                  offset:   4    4;
+               }
+               rel2 {
+                  relative: 0.0  1.0;
+                  offset:   4   -5;
+               }
+            }
+         }
+         part { name: "elm.swallow.end";
+            type: SWALLOW;
+            description { state: "default" 0.0;
+               fixed: 1 0;
+               align: 1.0 0.5;
+               aspect: 1.0 1.0;
+               aspect_preference: VERTICAL;
+               rel1 {
+                  relative: 1.0  0.0;
+                  offset:   -5    4;
+               }
+               rel2 {
+                  relative: 1.0  1.0;
+                  offset:   -5   -5;
+               }
+            }
+         }
+         part { name: "elm.text";
+            type:           TEXT;
+            effect:         SOFT_SHADOW;
+            mouse_events:   0;
+            scale: 1;
+            description {
+               state: "default" 0.0;
+//               min: 16 16;
+               rel1 {
+                  to_x:     "elm.swallow.icon";
+                  relative: 1.0  0.0;
+                  offset:   0 4;
+               }
+               rel2 {
+                  to_x:     "elm.swallow.end";
+                  relative: 0.0  1.0;
+                  offset:   -1 -5;
+               }
+               color: 0 0 0 255;
+               color3: 0 0 0 0;
+               text {
+                  font: "Sans";
+                  size: 10;
+                  min: 1 1;
+//                  min: 0 1;
+                  align: 0.0 0.5;
+               }
+            }
+            description { state: "selected" 0.0;
+               inherit: "default" 0.0;
+               color: 224 224 224 255;
+               color3: 0 0 0 64;
+            }
+         }
+         part { name: "fg1";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               visible: 0;
+               color: 255 255 255 0;
+               rel1.to: "bg";
+               rel2.relative: 1.0 0.5;
+               rel2.to: "bg";
+               image {
+                  normal: "bt_sm_hilight.png";
+                  border: 6 6 6 0;
+               }
+            }
+            description { state: "selected" 0.0;
+               inherit: "default" 0.0;
+               visible: 1;
+               color: 255 255 255 255;
+            }
+         }
+         part { name: "fg2";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               visible: 0;
+               color: 255 255 255 0;
+               rel1.to: "bg";
+               rel2.to: "bg";
+               image {
+                  normal: "bt_sm_shine.png";
+                  border: 6 6 6 0;
+               }
+            }
+            description { state: "selected" 0.0;
+               inherit: "default" 0.0;
+               visible: 1;
+               color: 255 255 255 255;
+            }
+         }
+         part {
+            name:           "event";
+            type:           RECT;
+            repeat_events: 1;
+            description {
+               state: "default" 0.0;
+               color: 0 0 0 0;
+            }
+         }
+      }
+      programs {
+         program {
+            name:    "go_active";
+            signal:  "elm,state,selected";
+            source:  "elm";
+            action:  STATE_SET "selected" 0.0;
+            target:  "bg";
+            target:  "fg1";
+            target:  "fg2";
+            target:  "elm.text";
+         }
+         program {
+            name:    "go_passive";
+            signal:  "elm,state,unselected";
+            source:  "elm";
+            action:  STATE_SET "default" 0.0;
+            target:  "bg";
+            target:  "fg1";
+            target:  "fg2";
+            target:  "elm.text";
+            transition: LINEAR 0.1;
+         }
+      }
+   }
+   group { name: "elm/genlist/item_odd/default/default";
+      data.item: "stacking" "below";
+      data.item: "selectraise" "on";
+      data.item: "labels" "elm.text";
+      data.item: "icons" "elm.swallow.icon elm.swallow.end";
+//      data.item: "states" "";
+      images {
+         image: "bt_sm_base1.png" COMP;
+         image: "bt_sm_shine.png" COMP;
+         image: "bt_sm_hilight.png" COMP;
+         image: "ilist_2.png" COMP;
+      }
+      parts {
+         part {
+            name: "base";
+            mouse_events: 0;
+            description {
+               state: "default" 0.0;
+               image {
+                  normal: "ilist_2.png";
+                  border: 2 2 2 2;
+               }
+               fill.smooth: 0;
+            }
+         }
+         part { name: "bg";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               visible: 0;
+               color: 255 255 255 0;
+               rel1 {
+                  relative: 0.0 0.0;
+                  offset: -5 -5;
+               }
+               rel2 {
+                  relative: 1.0 1.0;
+                  offset: 4 4;
+               }
+               image {
+                  normal: "bt_sm_base1.png";
+                  border: 6 6 6 6;
+               }
+            }
+            description { state: "selected" 0.0;
+               inherit: "default" 0.0;
+               visible: 1;
+               color: 255 255 255 255;
+               rel1 {
+                  relative: 0.0 0.0;
+                  offset: -2 -2;
+               }
+               rel2 {
+                  relative: 1.0 1.0;
+                  offset: 1 1;
+               }
+            }
+         }
+         part {
+            name:          "elm.swallow.icon";
+            type:          SWALLOW;
+            description { state:    "default" 0.0;
+               fixed: 1 0;
+               align:    0.0 0.5;
+               rel1 {
+                  relative: 0.0  0.0;
+                  offset:   4    4;
+               }
+               rel2 {
+                  relative: 0.0  1.0;
+                  offset:   4   -5;
+               }
+            }
+         }
+         part {
+            name:          "elm.swallow.end";
+            type:          SWALLOW;
+            description { state:    "default" 0.0;
+               fixed: 1 0;
+               align:    1.0 0.5;
+               rel1 {
+                  relative: 1.0  0.0;
+                  offset:   -5    4;
+               }
+               rel2 {
+                  relative: 1.0  1.0;
+                  offset:   -5   -5;
+               }
+            }
+         }
+         part {
+            name:           "elm.text";
+            type:           TEXT;
+            effect:         SOFT_SHADOW;
+            mouse_events:   0;
+            scale: 1;
+            description {
+               state: "default" 0.0;
+//               min:      16 16;
+               rel1 {
+                  to_x:     "elm.swallow.icon";
+                  relative: 1.0  0.0;
+                  offset:   0 4;
+               }
+               rel2 {
+                  to_x:     "elm.swallow.end";
+                  relative: 0.0  1.0;
+                  offset:   -1 -5;
+               }
+               color: 0 0 0 255;
+               color3: 0 0 0 0;
+               text {
+                  font: "Sans";
+                  size: 10;
+                  min: 1 1;
+//                  min: 0 1;
+                  align: 0.0 0.5;
+               }
+            }
+            description { state: "selected" 0.0;
+               inherit: "default" 0.0;
+               color: 224 224 224 255;
+               color3: 0 0 0 64;
+            }
+         }
+         part { name: "fg1";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               visible: 0;
+               color: 255 255 255 0;
+               rel1.to: "bg";
+               rel2.relative: 1.0 0.5;
+               rel2.to: "bg";
+               image {
+                  normal: "bt_sm_hilight.png";
+                  border: 6 6 6 0;
+               }
+            }
+            description { state: "selected" 0.0;
+               inherit: "default" 0.0;
+               visible: 1;
+               color: 255 255 255 255;
+            }
+         }
+         part { name: "fg2";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               visible: 0;
+               color: 255 255 255 0;
+               rel1.to: "bg";
+               rel2.to: "bg";
+               image {
+                  normal: "bt_sm_shine.png";
+                  border: 6 6 6 0;
+               }
+            }
+            description { state: "selected" 0.0;
+               inherit: "default" 0.0;
+               visible: 1;
+               color: 255 255 255 255;
+            }
+         }
+         part {
+            name:           "event";
+            type:           RECT;
+            repeat_events: 1;
+            description {
+               state: "default" 0.0;
+               color: 0 0 0 0;
+            }
+         }
+      }
+      programs {
+         program {
+            name:    "go_active";
+            signal:  "elm,state,selected";
+            source:  "elm";
+            action:  STATE_SET "selected" 0.0;
+            target:  "bg";
+            target:  "fg1";
+            target:  "fg2";
+            target:  "elm.text";
+         }
+         program {
+            name:    "go_passive";
+            signal:  "elm,state,unselected";
+            source:  "elm";
+            action:  STATE_SET "default" 0.0;
+            target:  "bg";
+            target:  "fg1";
+            target:  "fg2";
+            target:  "elm.text";
+            transition: LINEAR 0.1;
+         }
+      }
+   }
 }
index 162533e..a58b32f 100644 (file)
@@ -2086,13 +2086,13 @@ my_bt_29(void *data, Evas_Object *obj, void *event_info)
    evas_object_size_hint_weight_set(gl, 1.0, 1.0);
    evas_object_show(gl);
    
-   itc1.style = "default";
+   itc1.style          = "default";
    itc1.func.label_get = gl_label_get;
-   itc1.func.icon_get = gl_icon_get;
+   itc1.func.icon_get  = gl_icon_get;
    itc1.func.state_get = gl_state_get;
-   itc1.func.del = gl_del;
+   itc1.func.del       = gl_del;
 
-   for (i = 0; i < 2000; i++)
+   for (i = 0; i < 10000; i++)
      {
         gli = elm_genlist_item_append(gl, &itc1, (void *)i/* item data */, 
                                       NULL/* parent */, ELM_GENLIST_ITEM_NONE, 
index d6e4602..7368686 100644 (file)
@@ -540,17 +540,15 @@ extern "C" {
 //// (incomplete - medium priority)
 // * entry selection conflicts with finger scroll (make selection start/stop work on signals?)
 // * disabled not supported
-// * tab widget focusing (not useful for touchscreen tho...)
 // * on the fly theme changes - test (should work)
 // * need a hold-scroll counter in elm_widget
 // * add fullscreen mode on/off for windows
 // * hoversel only vertical right now - make horizontal
-// * set scaling per widget (and if scaling should be inherited by children)
 // * when entries are in a scroller and change size, the scroller shows scrollbars. fix. same for selecting. for 1 line entries in a scroller should only have scroll arrow indicators.
 // 
 //// (more widgets/features - medium priority)
-// * biglist widget (restricted format label + icon intended for massive lists)
-// * treeview widget (like biglist - but items can expand to sub-items)
+// * genlist widget (complex list widget - harder to use than normal simple list, but handles huge lists of items etc.)
+// * tree feature fir genlist widget (like biglist - but items can expand to sub-items)
 // * radio + group handling
 // * checkbox (like toggle)
 // * pager (for pushing/popping pages and going back and forward and flipping)
@@ -577,7 +575,7 @@ extern "C" {
 // * dialpad widget - need one with a phone dialpad
 // * file selector widget
 // * progress bar widget
-// * generic "tacho" widget (set min/max labels - and up to 3 intermediate labels)
+// * generic "tacho" widget (set min/max labels - and up to 3 intermediate labels etc.)
 // * status widget (busy, stalled, running, etc.)
 // * full window in window widget (so move/resize of window object does as you'd expect a child window to do within the canvas)
 // 
@@ -588,19 +586,24 @@ extern "C" {
 // * use evas's new box instead of a box smart
 // * use evas's table instead of a table smart
 // * use stack for win widget
+// * prepend or append theme files from code for an app to allow an app to augment the theme eithe rby forcibly overriding things with its own theme file (so it can ship some custom elements that always override user theme) and so it can also provide a final (even after default) fallback for "extended" styles of its own (but thus allowing themes to overried its extensions if they want)
+// * determine prefix of app dynamically and export calls to get prefix info
+// * load config from file
+// * load config from x prpoerty
+// * handle finger size property and on-the-fly changes like scaling does
 // * somehow a pdf(ps) viewer widget that doesnt make it gpl (lgpl)
-// * emotion widget?
+// * emotion widget
 // * ewebkit widget
+// * flash (gnash) widget
 // * need url and path entry modes for vkbd
 // * return list of toplevel window objects
-// * widgets should show who is focused (not useful for touchscreen)
 // * focus should have an object that is layered above all others (definable layer) that moves + resizes (slides about - animated) from one focused widget to the next for focus. also emit focus/unfocus signals too
 // * scroller could do with page up/down/left/right buttons and and idea of a page size
 // * current sizing tree inefficient
 // * need a way to filter entry data for entry (eg for phone numbers)
 // * win should emit signals based on vkbd type - if it gets a message and is a vkbd win
 // * win needs a way of setting aspect too
-// * use the wrong call on the wrong widget and *BOOM*
+// * use the wrong call on the wrong widget and *BOOM* ... crashland
 // 
 //////////////////////////////////////////////////////////////////////////////
 #endif
index 2ae8051..d852c6b 100644 (file)
@@ -8,6 +8,7 @@ typedef struct _Pan Pan;
 
 struct _Widget_Data
 {
+   Evas_Object *obj;
    Evas_Object *scr;
    Evas_Object *pan_smart;
    Evas_Object *content;
@@ -15,6 +16,9 @@ struct _Widget_Data
    Eina_Inlist *blocks;
    Pan *pan;
    Evas_Coord pan_x, pan_y, minw, minh;
+   Ecore_Job *calc_job;
+   Ecore_Idler *queue_idler;
+   Eina_List *queue;
    Evas_Bool min_w : 1;
    Evas_Bool min_h : 1;
 };
@@ -24,7 +28,6 @@ struct _Item_Block
    Eina_Inlist __header;
    int count;
    Widget_Data *wd;
-   Evas_Object *obj;
    Eina_List *items;
    Evas_Coord x, y, w, h, minw, minh;
    Evas_Bool realized : 1;
@@ -34,17 +37,11 @@ struct _Item_Block
 struct _Item
 {
    Eina_Inlist __header;
+   Widget_Data *wd;
    Item_Block *block;
-   Eina_Inlist *subblocks; // not done yet
-   Eina_Inlist *subitems; // not done yet
-   
+   Eina_Inlist *subblocks; // FIXME: not done yet
+   Eina_Inlist *subitems; // FIXME: not done yet
    Evas_Coord x, y, w, h, minw, minh;
-   Evas_Bool realized : 1;
-   Evas_Bool selected : 1;
-   Evas_Bool expanded : 1; // not done yet
-   Evas_Bool disabled : 1;
-   Evas_Bool mincalcd : 1;
-   
    const Elm_Genlist_Item_Class *itc;
    const void *data;
    Elm_Genlist_Item *parent; // not done yet
@@ -55,6 +52,15 @@ struct _Item
    } func;
    
    Evas_Object *base;
+   Eina_List *labels, *icons, *states;
+   
+   Evas_Bool realized : 1;
+   Evas_Bool selected : 1;
+   Evas_Bool expanded : 1; // FIXME: not done yet
+   Evas_Bool disabled : 1;
+   Evas_Bool mincalcd : 1;
+   Evas_Bool queued : 1;
+   
 };
 
 struct _Pan {
@@ -154,135 +160,90 @@ _resize(void *data, Evas *e, Evas_Object *obj, void *event_info)
    _sizing_eval(data);
 }
 
-static void
-_pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
-{
-   Pan *sd = evas_object_smart_data_get(obj);
-   Evas_Coord ow, oh;
-   if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return;
-   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
-   ow = sd->wd->minw - ow;
-   if (ow < 0) ow = 0;
-   oh = sd->wd->minh - oh;
-   if (oh < 0) oh = 0;
-   if (x < 0) x = 0;
-   if (y < 0) y = 0;
-   if (x > ow) x = ow;
-   if (y > oh) y = oh;
-   sd->wd->pan_x = x;
-   sd->wd->pan_y = y;
-   evas_object_smart_changed(obj);
-}
-
-static void
-_pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
-{
-   Pan *sd = evas_object_smart_data_get(obj);
-   if (x) *x = sd->wd->pan_x;
-   if (y) *y = sd->wd->pan_y;
-}
-
-static void
-_pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
-{    
-   Pan *sd = evas_object_smart_data_get(obj);
-   Evas_Coord ow, oh;
-   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
-   ow = sd->wd->minw - ow;
-   if (ow < 0) ow = 0;
-   oh = sd->wd->minh - oh;
-   if (oh < 0) oh = 0;
-   if (x) *x = ow; 
-   if (y) *y = oh; 
-}
-
-static void
-_pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
-{
-   Pan *sd = evas_object_smart_data_get(obj);
-   if (w) *w = sd->wd->minw;
-   if (h) *h = sd->wd->minh;
-}
-
-static void
-_pan_add(Evas_Object *obj)
-{
-   Pan *sd;
-   Evas_Object_Smart_Clipped_Data *cd;
-
-   _pan_sc.add(obj);
-   cd = evas_object_smart_data_get(obj);
-   sd = calloc(1, sizeof(Pan));
-   if (!sd) return;
-   sd->__clipped_data = *cd;
-   free(cd);
-   evas_object_smart_data_set(obj, sd);
-}
-   
-static void
-_pan_del(Evas_Object *obj)
+static Eina_List *
+_stringlist_get(const char *str)
 {
-   Pan *sd = evas_object_smart_data_get(obj);
-   if (!sd) return;
-   _pan_sc.del(obj);
+   Eina_List *list = NULL;
+   const char *s, *b;
+   if (!str) return NULL;
+   for (b = s = str; 1; s++)
+     {
+        if ((*s == ' ') || (*s == 0))
+          {
+             char *t = malloc(s - b + 1);
+             if (t)
+               {
+                  strncpy(t, b, s - b);
+                  t[s - b] = 0;
+                  list = eina_list_append(list, eina_stringshare_add(t));
+                  free(t);
+               }
+             b = s + 1;
+          }
+        if (*s == 0) break;
+     }
+   return list;
 }
 
 static void
-_pan_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
+_stringlist_free(Eina_List *list)
 {
-   Evas_Coord ow, oh;
-   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
-   if ((ow == w) && (oh == h)) return;
-   evas_object_smart_changed(obj);
+   while (list)
+     {
+        eina_stringshare_del(list->data);
+        list = eina_list_remove_list(list, list);
+     }
 }
 
-
-
-
-
-
 static void
-_item_realize(Item *it, int in)
+_item_realize(Item *it, int in, int calc)
 {
    const char *stacking;
+   char buf[1024];
    
    if (it->realized) return;
-   it->base = edje_object_add(evas_object_evas_get(it->block->obj));
+   it->base = edje_object_add(evas_object_evas_get(it->wd->obj));
+   evas_object_smart_member_add(it->base, it->wd->pan_smart);
+   elm_widget_sub_object_add(it->wd->obj, it->base);
+   if (in & 0x1)
+     snprintf(buf, sizeof(buf), "%s/%s", "item_odd", it->itc->style);
+   else
+     snprintf(buf, sizeof(buf), "%s/%s", "item", it->itc->style);
+   _elm_theme_set(it->base, "genlist", buf, "default");
+   if (!calc)
+     {
+        stacking = edje_object_data_get(it->base, "stacking");
+        if (stacking)
+          {
+             if (!strcmp(stacking, "below")) evas_object_lower(it->base);
+             else if (!strcmp(stacking, "above")) evas_object_raise(it->base);
+          }
 // FIXME: hook callbacks   
 //   evas_object_event_callback_add(it->base, EVAS_CALLBACK_MOUSE_DOWN,
 //                                  _mouse_down, it);
 //   evas_object_event_callback_add(it->base, EVAS_CALLBACK_MOUSE_UP,
 //                                  _mouse_up, it);
-   evas_object_smart_member_add(it->base, it->block->wd->pan_smart);
-   elm_widget_sub_object_add(it->block->obj, it->base);
-   if (in & 0x1)
-     _elm_theme_set(it->base, "list", "item_odd", "default");
-   else
-     _elm_theme_set(it->base, "list", "item", "default");
-   stacking = edje_object_data_get(it->base, "stacking");
-   if (stacking)
-     {
-        if (!strcmp(stacking, "below"))
-          evas_object_lower(it->base);
-        else if (!strcmp(stacking, "above"))
-          evas_object_raise(it->base);
      }
+   
    if (it->itc->func.label_get)
      {
-        char *s = it->itc->func.label_get(it->data, "xxx");
-        if (s)
+        Eina_List *l;
+        
+        it->labels = _stringlist_get(edje_object_data_get(it->base, "labels"));
+        for (l = it->labels; l; l = l->next)
           {
-             edje_object_part_text_set(it->base, "elm.text", s);
-             free(s);
+             const char *key = l->data;
+             char *s = it->itc->func.label_get(it->data, l->data);
+             if (s)
+               {
+                  edje_object_part_text_set(it->base, l->data, s);
+                  free(s);
+               }
           }
      }
-   // FIXME: need to get all labels, all icons and all states and all labels
-   evas_object_show(it->base);
    if (!it->mincalcd)
      {
-        Evas_Coord mw, mh;
-        
-        mw = mh = -1;
+        Evas_Coord mw = -1, mh = -1;
         elm_coords_finger_size_adjust(1, &mw, 1, &mh);
         edje_object_size_min_restricted_calc(it->base, &mw, &mh, mw, mh);
         elm_coords_finger_size_adjust(1, &mw, 1, &mh);
@@ -290,6 +251,7 @@ _item_realize(Item *it, int in)
         it->minh = mh;
         it->mincalcd = 1;
      }
+   if (!calc) evas_object_show(it->base);
    it->realized = 1;
 }
 
@@ -299,6 +261,12 @@ _item_unrealize(Item *it)
    if (!it->realized) return;
    evas_object_del(it->base);
    it->base = NULL;
+   _stringlist_free(it->labels);
+   it->labels = NULL;
+   _stringlist_free(it->icons);
+   it->icons = NULL;
+   _stringlist_free(it->states);
+   it->states = NULL;
    it->realized = 0;
 }
 
@@ -307,12 +275,17 @@ _item_block_recalc(Item_Block *itb, int in)
 {
    Eina_List *l;
    Evas_Coord minw = 0, minh = 0;
-   
+
    for (l = itb->items; l; l = l->next)
      {
         Item *it = l->data;
-        _item_realize(it, in);
-        if (!itb->realized) _item_unrealize(it);
+        if (!itb->realized)
+          {
+             _item_realize(it, in, 1);
+             _item_unrealize(it);
+          }
+        else
+          _item_realize(it, in, 0);
         minh += it->minh;
         if (minw < it->minw) minw = it->minw;
         in++;
@@ -320,6 +293,8 @@ _item_block_recalc(Item_Block *itb, int in)
    itb->minw = minw;
    itb->minh = minh;
    itb->changed = 0;
+   /* force an evas norender to garbage collect deleted objects */
+   evas_norender(evas_object_evas_get(itb->wd->obj));
 }
 
 static void
@@ -330,7 +305,7 @@ _item_block_realize(Item_Block *itb, int in)
    for (l = itb->items; l; l = l->next)
      {
         Item *it = l->data;
-        _item_realize(it, in);
+        _item_realize(it, in, 0);
         in++;
      }
    itb->realized = 1;
@@ -369,20 +344,21 @@ _item_block_position(Item_Block *itb)
         evas_object_move(it->base, 
                          ox + itb->x + it->x - itb->wd->pan_x,
                          oy + itb->y + it->y - itb->wd->pan_y);
+        evas_object_show(it->base);
         y += it->h;
      }
    itb->realized = 1;
 }
 
 static void
-_pan_calculate(Evas_Object *obj)
+_calc_job(void *data)
 {
-   Pan *sd = evas_object_smart_data_get(obj);
+   Widget_Data *wd = data;
    Eina_Inlist *il;
    Evas_Coord minw = 0, minh = 0, x = 0, y = 0, ow, oh;
    int bn, in;
    
-   for (bn = 0, in = 0, il = sd->wd->blocks; il; il = il->next, bn++)
+   for (bn = 0, in = 0, il = wd->blocks; il; il = il->next, bn++)
      {
         Item_Block *itb = (Item_Block *)il;
         if (itb->changed)
@@ -397,28 +373,122 @@ _pan_calculate(Evas_Object *obj)
         y += itb->minh;
         in += itb->count;
      }
-   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
+   evas_object_geometry_get(wd->pan_smart, NULL, NULL, &ow, &oh);
    if (minw < ow) minw = ow;
-   if ((minw != sd->wd->minw) || (minh != sd->wd->minh))
+   if ((minw != wd->minw) || (minh != wd->minh))
      {
-        sd->wd->minw = minw;
-        sd->wd->minh = minh;
-        evas_object_smart_callback_call(obj, "changed", NULL);
+        wd->minw = minw;
+        wd->minh = minh;
+        evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
      }
-   // FIXME: calcualte new geom
+   wd->calc_job = NULL;
+   evas_object_smart_changed(wd->pan_smart);
+}
+
+static void
+_pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
+{
+   Pan *sd = evas_object_smart_data_get(obj);
+   Evas_Coord ow, oh;
+   if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return;
+   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
+   ow = sd->wd->minw - ow;
+   if (ow < 0) ow = 0;
+   oh = sd->wd->minh - oh;
+   if (oh < 0) oh = 0;
+   if (x < 0) x = 0;
+   if (y < 0) y = 0;
+   if (x > ow) x = ow;
+   if (y > oh) y = oh;
+   sd->wd->pan_x = x;
+   sd->wd->pan_y = y;
+   evas_object_smart_changed(obj);
+}
+
+static void
+_pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
+{
+   Pan *sd = evas_object_smart_data_get(obj);
+   if (x) *x = sd->wd->pan_x;
+   if (y) *y = sd->wd->pan_y;
+}
+
+static void
+_pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
+{    
+   Pan *sd = evas_object_smart_data_get(obj);
+   Evas_Coord ow, oh;
+   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
+   ow = sd->wd->minw - ow;
+   if (ow < 0) ow = 0;
+   oh = sd->wd->minh - oh;
+   if (oh < 0) oh = 0;
+   if (x) *x = ow; 
+   if (y) *y = oh; 
+}
+
+static void
+_pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
+{
+   Pan *sd = evas_object_smart_data_get(obj);
+   if (w) *w = sd->wd->minw;
+   if (h) *h = sd->wd->minh;
+}
+
+static void
+_pan_add(Evas_Object *obj)
+{
+   Pan *sd;
+   Evas_Object_Smart_Clipped_Data *cd;
+
+   _pan_sc.add(obj);
+   cd = evas_object_smart_data_get(obj);
+   sd = calloc(1, sizeof(Pan));
+   if (!sd) return;
+   sd->__clipped_data = *cd;
+   free(cd);
+   evas_object_smart_data_set(obj, sd);
+}
    
+static void
+_pan_del(Evas_Object *obj)
+{
+   Pan *sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   _pan_sc.del(obj);
+}
+
+static void
+_pan_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
+{
+   Pan *sd = evas_object_smart_data_get(obj);
+   Evas_Coord ow, oh;
+   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
+   if ((ow == w) && (oh == h)) return;
+   if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
+   sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
+}
+
+static void
+_pan_calculate(Evas_Object *obj)
+{
+   Pan *sd = evas_object_smart_data_get(obj);
+   Eina_Inlist *il;
+   Evas_Coord ow, oh;
+   int bn, in;
+
+   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
    for (bn = 0, in = 0, il = sd->wd->blocks; il; il = il->next, bn++)
      {
         Item_Block *itb = (Item_Block *)il;
-        itb->w = minw;
+        itb->w = sd->wd->minw;
         if (ELM_RECTS_INTERSECT(itb->x - sd->wd->pan_x, 
                                 itb->y - sd->wd->pan_y, 
                                 itb->w, itb->h,
                                 0, 0, ow, oh))
           {
-             if (!itb->realized)
+             if ((!itb->realized) || (itb->changed))
                {
-                  printf("REALIZE BN # %i [%i %i, %ix%i]\n", bn, itb->x, itb->y, itb->w, itb->h);
                   _item_block_realize(itb, in);
                }
              _item_block_position(itb);
@@ -427,7 +497,6 @@ _pan_calculate(Evas_Object *obj)
           {
              if (itb->realized)
                {
-                  printf("UNREALIZE BN # %i [%i %i, %ix%i]\n", bn, itb->x, itb->y, itb->w, itb->h);
                   _item_block_unrealize(itb);
                }
           }
@@ -453,6 +522,8 @@ elm_genlist_add(Evas_Object *parent)
    
    wd->scr = elm_smart_scroller_add(e);
    elm_widget_resize_object_set(obj, wd->scr);
+   
+   wd->obj = obj;
 
    if (!smart)
      {
@@ -489,7 +560,7 @@ elm_genlist_add(Evas_Object *parent)
 }
 
 static Item *
-_item_new(Evas_Object *obj, const Elm_Genlist_Item_Class *itc, 
+_item_new(Widget_Data *wd, const Elm_Genlist_Item_Class *itc, 
           const void *data, Elm_Genlist_Item *parent, 
           Elm_Genlist_Item_Flags flags,
           void (*func) (void *data, Evas_Object *obj, void *event_info), const void *func_data)
@@ -498,6 +569,7 @@ _item_new(Evas_Object *obj, const Elm_Genlist_Item_Class *itc,
    
    it = calloc(1, sizeof(Item));
    if (!it) return NULL;
+   it->wd = wd;
    it->itc = itc;
    it->data = data;
    it->parent = parent;
@@ -508,7 +580,7 @@ _item_new(Evas_Object *obj, const Elm_Genlist_Item_Class *itc,
 }
 
 static void
-_item_block_add(Widget_Data *wd, Evas_Object *obj, Item *it, Item *itpar, Item *itrel)
+_item_block_add(Widget_Data *wd, Item *it, Item *itpar, Item *itrel, int before)
 {
    Item_Block *itb;
    
@@ -517,9 +589,28 @@ _item_block_add(Widget_Data *wd, Evas_Object *obj, Item *it, Item *itpar, Item *
         newblock:
         itb = calloc(1, sizeof(Item_Block));
         if (!itb) return;
-        wd->blocks = eina_inlist_append(wd->blocks, (Eina_Inlist *)itb);
-        itb->obj = obj;
         itb->wd = wd;
+        if (!it->parent)
+          {
+             if (itrel)
+               {
+                  if (!itrel->block)
+                    printf("EEEK itrel has no block!\n");
+                  else
+                    {
+                       if (before)
+                         wd->blocks = eina_inlist_prepend_relative(wd->blocks, (Eina_Inlist *)itb, (Eina_Inlist *)(itrel->block));
+                       else
+                         wd->blocks = eina_inlist_append_relative(wd->blocks, (Eina_Inlist *)itb, (Eina_Inlist *)(itrel->block));
+                    }
+               }
+             else
+               wd->blocks = eina_inlist_append(wd->blocks, (Eina_Inlist *)itb);
+          }
+        else
+          {
+             // FIXME: tree not handled.
+          }
      }
    else
      {
@@ -530,7 +621,62 @@ _item_block_add(Widget_Data *wd, Evas_Object *obj, Item *it, Item *itpar, Item *
    itb->count++;
    itb->changed = 1;
    it->block = itb;
-   evas_object_smart_changed(wd->pan_smart);
+   if (itb->wd->calc_job) ecore_job_del(itb->wd->calc_job);
+   itb->wd->calc_job = ecore_job_add(_calc_job, itb->wd);
+}
+
+static int
+_item_idler(void *data)
+{
+   Widget_Data *wd = data;
+   int n;
+   
+   for (n = 0; (wd->queue) && (n < 16); n++)
+     {
+        Item *itrel, *it;
+        
+        it = wd->queue->data;
+        wd->queue = eina_list_remove_list(wd->queue, wd->queue);
+        it->queued = 0;
+        if (!it->parent)
+          {
+             itrel = (Item *)(((Eina_Inlist *)it)->prev);
+             if (itrel) _item_block_add(wd, it, NULL, itrel, 0);
+             else
+               {
+                  itrel = (Item *)(((Eina_Inlist *)it)->next);
+                  if (itrel && itrel->queued)
+                    _item_block_add(wd, it, NULL, NULL, 0);
+                  else
+                    _item_block_add(wd, it, NULL, itrel, 1);
+               }
+          }
+        else
+          {
+             // FIXME: tree. not done yet
+          }
+     }
+   if (n > 0)
+     {
+        // queue a draw
+        if (wd->calc_job) ecore_job_del(wd->calc_job);
+        wd->calc_job = ecore_job_add(_calc_job, wd);
+     }
+   if (!wd->queue)
+     {
+        wd->queue_idler = NULL;
+        return 0;
+     }
+   return 1;
+}
+
+static void
+_item_queue(Widget_Data *wd, Item *it)
+{
+   if (it->queued) return;
+   if (!wd->queue_idler) wd->queue_idler = ecore_idler_add(_item_idler, wd);
+   it->queued = 1;
+   wd->queue = eina_list_append(wd->queue, it);
 }
 
 EAPI Elm_Genlist_Item *
@@ -540,21 +686,16 @@ elm_genlist_item_append(Evas_Object *obj, const Elm_Genlist_Item_Class *itc,
                         void (*func) (void *data, Evas_Object *obj, void *event_info), const void *func_data)
 {
    Widget_Data *wd = elm_widget_data_get(obj);
-   Item *itpar, *itrel;
-   Item *it = _item_new(obj, itc, data, parent, flags, func, func_data);
+   Item *itpar;
+   Item *it = _item_new(wd, itc, data, parent, flags, func, func_data);
    if (!it) return NULL;
-   if (!parent)
-     {
-        wd->items = eina_inlist_append(wd->items, (Eina_Inlist *)it);
-        itrel = (Item *)(((Eina_Inlist *)it)->prev);
-        _item_block_add(wd, obj, it, NULL, itrel);
-     }
+   if (!it->parent)
+     wd->items = eina_inlist_append(wd->items, (Eina_Inlist *)it);
    else
      {
         // FIXME: tree. not done yet
-        itpar = (Item *)parent;
-        itpar->subitems = eina_inlist_append(itpar->subitems, (Eina_Inlist *)it);
      }
+   _item_queue(wd, it);
    return (Elm_Genlist_Item *)it;
 }