[Elm] File selector now a layout.
authorGustavo Lima Chaves <glima@profusion.mobi>
Thu, 3 May 2012 22:44:26 +0000 (22:44 +0000)
committerGustavo Lima Chaves <glima@profusion.mobi>
Thu, 3 May 2012 22:44:26 +0000 (22:44 +0000)
SVN revision: 70742

src/lib/elc_fileselector.c
src/lib/elc_fileselector.h

index 148c73d..c2a2d89 100644 (file)
  *  - Filter support
  */
 
-#ifdef HAVE_CONFIG_H
-# include "elementary_config.h"
-#endif
+#include <Elementary.h>
+#include "elm_priv.h"
+#include "elm_widget_layout.h"
 
 #ifdef HAVE_EIO
 # include <Eio.h>
 #endif
 
-#include <Elementary.h>
-#include "elm_priv.h"
+static const char FILESELECTOR_SMART_NAME[] = "elm_fileselector";
 
-typedef struct _Widget_Data Widget_Data;
+typedef struct _Elm_Fileselector_Smart_Data Elm_Fileselector_Smart_Data;
 
-struct _Widget_Data
+struct _Elm_Fileselector_Smart_Data
 {
-   EINA_REFCOUNT;
+   Elm_Layout_Smart_Data base;
 
-   Evas_Object *edje;
-   Evas_Object *filename_entry;
-   Evas_Object *path_entry;
-   Evas_Object *files_list;
-   Evas_Object *files_grid;
-   Evas_Object *up_button;
-   Evas_Object *home_button;
+   EINA_REFCOUNT;
 
-   Evas_Object *ok_button;
-   Evas_Object *cancel_button;
+   Evas_Object          *filename_entry;
+   Evas_Object          *path_entry;
+   Evas_Object          *files_list;
+   Evas_Object          *files_grid;
+   Evas_Object          *up_button;
+   Evas_Object          *home_button;
+   Evas_Object          *ok_button;
+   Evas_Object          *cancel_button;
 
-   const char  *path;
-   const char  *selection;
-   Ecore_Idler *sel_idler;
+   const char           *path;
+   const char           *selection;
+   Ecore_Idler          *sel_idler;
 
-   const char  *path_separator;
+   const char           *path_separator;
 
 #ifdef HAVE_EIO
-   Eio_File    *current;
+   Eio_File             *current;
 #endif
 
    Elm_Fileselector_Mode mode;
 
-   Eina_Bool    only_folder : 1;
-   Eina_Bool    expand : 1;
+   Eina_Bool             only_folder : 1;
+   Eina_Bool             expand : 1;
 };
 
 struct sel_data
@@ -60,202 +59,182 @@ struct sel_data
    const char  *path;
 };
 
-typedef struct _Widget_Request Widget_Request;
-struct _Widget_Request
+typedef struct _Listing_Request Listing_Request;
+struct _Listing_Request
 {
-   Widget_Data *wd;
-   Elm_Object_Item *parent;
+   Elm_Fileselector_Smart_Data *sd;
+   Elm_Object_Item             *parent_it;
 
-   Evas_Object *obj;
-   const char *path;
-   Eina_Bool first : 1;
+   Evas_Object                 *obj;
+   const char                  *path;
+   Eina_Bool                    first : 1;
 };
 
 typedef enum {
-  ELM_DIRECTORY = 0,
-  ELM_FILE_IMAGE = 1,
-  ELM_FILE_UNKNOW = 2,
-  ELM_FILE_LAST
+   ELM_DIRECTORY = 0,
+   ELM_FILE_IMAGE = 1,
+   ELM_FILE_UNKNOW = 2,
+   ELM_FILE_LAST
 } Elm_Fileselector_Type;
 
 static Elm_Genlist_Item_Class *list_itc[ELM_FILE_LAST];
 static Elm_Gengrid_Item_Class *grid_itc[ELM_FILE_LAST];
 
-static const char *widtype = NULL;
-
 static const char SIG_DIRECTORY_OPEN[] = "directory,open";
 static const char SIG_DONE[] = "done";
 static const char SIG_SELECTED[] = "selected";
-static const Evas_Smart_Cb_Description _signals[] = {
+static const Evas_Smart_Cb_Description _smart_callbacks[] = {
    {SIG_DIRECTORY_OPEN, "s"},
    {SIG_DONE, "s"},
    {SIG_SELECTED, "s"},
    {NULL, NULL}
 };
 
-static void _populate(Evas_Object      *obj,
-                      const char       *path,
-                      Elm_Object_Item  *parent);
-static void _do_anchors(Evas_Object *obj,
-                        const char  *path);
-
-/***  ELEMENTARY WIDGET  ***/
-static void
-_widget_data_free(Widget_Data *wd)
-{
-   if (wd->path) eina_stringshare_del(wd->path);
-   if (wd->selection) eina_stringshare_del(wd->selection);
-   if (wd->sel_idler)
-     {
-        void *sd;
-
-        sd = ecore_idler_del(wd->sel_idler);
-        free(sd);
-     }
-   free(wd);
-}
+#define ELM_FILESELECTOR_DATA_GET(o, sd) \
+  Elm_Fileselector_Smart_Data * sd = evas_object_smart_data_get(o)
 
-static void
-_del_hook(Evas_Object *obj)
-{
-   Widget_Data *wd;
-   int i;
+#define ELM_FILESELECTOR_DATA_GET_OR_RETURN(o, ptr)  \
+  ELM_FILESELECTOR_DATA_GET(o, ptr);                 \
+  if (!ptr)                                          \
+    {                                                \
+       CRITICAL("No widget data for object %p (%s)", \
+                o, evas_object_type_get(o));         \
+       return;                                       \
+    }
 
-   wd = elm_widget_data_get(obj);
-   if (!wd) return;
+#define ELM_FILESELECTOR_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
+  ELM_FILESELECTOR_DATA_GET(o, ptr);                         \
+  if (!ptr)                                                  \
+    {                                                        \
+       CRITICAL("No widget data for object %p (%s)",         \
+                o, evas_object_type_get(o));                 \
+       return val;                                           \
+    }
 
-   for (i = 0; i < ELM_FILE_LAST; ++i)
-     {
-        elm_genlist_item_class_free(list_itc[i]);
-        elm_gengrid_item_class_free(grid_itc[i]);
-     }
+#define ELM_FILESELECTOR_CHECK(obj)                 \
+  if (!obj || !elm_widget_type_check                \
+        ((obj), FILESELECTOR_SMART_NAME, __func__)) \
+    return
 
-#ifdef HAVE_EIO
-   if (wd->current)
-     eio_file_cancel(wd->current);
-#endif
+/* Inheriting from elm_layout. Besides, we need no more than what is
+ * there */
+EVAS_SMART_SUBCLASS_NEW
+  (FILESELECTOR_SMART_NAME, _elm_fileselector, Elm_Layout_Smart_Class,
+  Elm_Layout_Smart_Class, elm_layout_smart_class_get, _smart_callbacks);
 
-   wd->files_list = NULL;
-   wd->files_grid = NULL;
+/* final routine on deletion */
+static void
+_elm_fileselector_smart_del_do(Elm_Fileselector_Smart_Data *sd)
+{
+   if (sd->path) eina_stringshare_del(sd->path);
+   if (sd->selection) eina_stringshare_del(sd->selection);
+   if (sd->sel_idler) free(ecore_idler_del(sd->sel_idler));
 
-   EINA_REFCOUNT_UNREF(wd)
-     _widget_data_free(wd);
+   ELM_WIDGET_CLASS(_elm_fileselector_parent_sc)->base.del
+     (ELM_WIDGET_DATA(sd)->obj);
 }
 
 static void
-_sizing_eval(Evas_Object *obj)
+_elm_fileselector_smart_sizing_eval(Evas_Object *obj)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
    Evas_Coord minw = -1, minh = -1;
-   if (!wd) return;
+
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
+
    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
-   edje_object_size_min_restricted_calc(wd->edje, &minw, &minh, minw, minh);
+   edje_object_size_min_restricted_calc
+     (ELM_WIDGET_DATA(sd)->resize_obj, &minw, &minh, minw, minh);
    evas_object_size_hint_min_set(obj, minw, minh);
 }
 
 static void
 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   elm_widget_mirrored_set(wd->cancel_button, rtl);
-   elm_widget_mirrored_set(wd->ok_button, rtl);
-   elm_widget_mirrored_set(wd->files_list, rtl);
-   elm_widget_mirrored_set(wd->up_button, rtl);
-   elm_widget_mirrored_set(wd->home_button, rtl);
-   edje_object_mirrored_set(wd->edje, rtl);
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
+
+   elm_widget_mirrored_set(sd->cancel_button, rtl);
+   elm_widget_mirrored_set(sd->ok_button, rtl);
+   elm_widget_mirrored_set(sd->files_list, rtl);
+   elm_widget_mirrored_set(sd->up_button, rtl);
+   elm_widget_mirrored_set(sd->home_button, rtl);
 }
 
-static void
-_theme_hook(Evas_Object *obj)
+static Eina_Bool
+_elm_fileselector_smart_theme(Evas_Object *obj)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
-   const char *style = elm_widget_style_get(obj);
+   const char *style;
    const char *data;
    char buf[1024];
 
-   if (!wd) return;
-   _elm_widget_mirrored_reload(obj);
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
 
-   _elm_theme_object_set(obj, wd->edje, "fileselector", "base", style);
+   if (!ELM_WIDGET_CLASS(_elm_fileselector_parent_sc)->theme(obj)) return EINA_FALSE;
 
-   if (elm_object_disabled_get(obj))
-     edje_object_signal_emit(wd->edje, "elm,state,disabled", "elm");
+   style = elm_widget_style_get(obj);
+   _mirrored_set(obj, elm_widget_mirrored_get(obj));
 
-   data = edje_object_data_get(wd->edje, "path_separator");
-   if (data)
-     wd->path_separator = data;
-   else
-     wd->path_separator = "/";
+   data = edje_object_data_get
+       (ELM_WIDGET_DATA(sd)->resize_obj, "path_separator");
+   if (data) sd->path_separator = data;
+   else sd->path_separator = "/";
 
-   if (!style) style = "default";
    snprintf(buf, sizeof(buf), "fileselector/%s", style);
 
-#define SWALLOW(part_name, object_ptn)                                \
-  if (object_ptn)                                                     \
-    {                                                                 \
-       elm_widget_style_set(object_ptn, buf);                         \
-       if (edje_object_part_swallow(wd->edje, part_name, object_ptn)) \
-         evas_object_show(object_ptn);                                \
-       else                                                           \
-         evas_object_hide(object_ptn);                                \
+#define SWALLOW(part_name, object_ptn)                          \
+  if (object_ptn)                                               \
+    {                                                           \
+       elm_widget_style_set(object_ptn, buf);                   \
+       if (!elm_layout_content_set(obj, part_name, object_ptn)) \
+         evas_object_hide(object_ptn);                          \
     }
-   SWALLOW("elm.swallow.up", wd->up_button);
-   SWALLOW("elm.swallow.home", wd->home_button);
 
-   if (wd->mode == ELM_FILESELECTOR_LIST)
+   SWALLOW("elm.swallow.up", sd->up_button);
+   SWALLOW("elm.swallow.home", sd->home_button);
+
+   if (sd->mode == ELM_FILESELECTOR_LIST)
      {
-        if (edje_object_part_swallow(wd->edje, "elm.swallow.files",
-                                     wd->files_list))
-          {
-             evas_object_show(wd->files_list);
-             evas_object_hide(wd->files_grid);
-          }
-        else
-          evas_object_hide(wd->files_list);
+        if (elm_layout_content_set(obj, "elm.swallow.files", sd->files_list))
+          evas_object_hide(sd->files_grid);
+        else evas_object_hide(sd->files_list);
      }
    else
      {
-        if (edje_object_part_swallow(wd->edje, "elm.swallow.files",
-                                     wd->files_grid))
-          {
-             evas_object_show(wd->files_grid);
-             evas_object_hide(wd->files_list);
-          }
-        else
-          evas_object_hide(wd->files_grid);
+        if (elm_layout_content_set(obj, "elm.swallow.files", sd->files_grid))
+          evas_object_hide(sd->files_list);
+        else evas_object_hide(sd->files_grid);
      }
 
-   SWALLOW("elm.swallow.filename", wd->filename_entry);
-   SWALLOW("elm.swallow.path", wd->path_entry);
+   SWALLOW("elm.swallow.filename", sd->filename_entry);
+   SWALLOW("elm.swallow.path", sd->path_entry);
 
    snprintf(buf, sizeof(buf), "fileselector/actions/%s", style);
-   SWALLOW("elm.swallow.cancel", wd->cancel_button);
-   SWALLOW("elm.swallow.ok", wd->ok_button);
+   SWALLOW("elm.swallow.cancel", sd->cancel_button);
+   SWALLOW("elm.swallow.ok", sd->ok_button);
+
 #undef SWALLOW
 
-   edje_object_message_signal_process(wd->edje);
-   _mirrored_set(obj, elm_widget_mirrored_get(obj));
-   edje_object_scale_set
-     (wd->edje, elm_widget_scale_get(obj) * _elm_config->scale);
-   _sizing_eval(obj);
+   edje_object_message_signal_process(ELM_WIDGET_DATA(sd)->resize_obj);
+
+   elm_layout_sizing_eval(obj);
+
+   return EINA_TRUE;
 }
 
-/***  GENLIST "MODEL"  ***/
+/***  GENLIST/GENGRID "MODEL"  ***/
 static char *
-_itc_text_get(void              *data,
-               Evas_Object *obj   __UNUSED__,
-               const char *source __UNUSED__)
+_itc_text_get(void *data,
+              Evas_Object *obj   __UNUSED__,
+              const char *source __UNUSED__)
 {
-   return elm_entry_utf8_to_markup(ecore_file_file_get(data)); /* NOTE this will be
-                                                                * free() by the
-                                                                * caller */
+   return elm_entry_utf8_to_markup
+            (ecore_file_file_get(data)); /* NOTE this will be free()'d by
+                                          * the caller */
 }
 
 static Evas_Object *
-_itc_icon_folder_get(void        *data __UNUSED__,
+_itc_icon_folder_get(void *data __UNUSED__,
                      Evas_Object *obj,
-                     const char  *source)
+                     const char *source)
 {
    Evas_Object *ic;
 
@@ -264,15 +243,14 @@ _itc_icon_folder_get(void        *data __UNUSED__,
    ic = elm_icon_add(obj);
    elm_icon_standard_set(ic, "folder");
 
-   evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL,
-                                    1, 1);
+   evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
    return ic;
 }
 
 static Evas_Object *
-_itc_icon_image_get(void        *data,
+_itc_icon_image_get(void *data,
                     Evas_Object *obj,
-                    const char  *source)
+                    const char *source)
 {
    const char *filename = data;
    Evas_Object *ic;
@@ -283,15 +261,14 @@ _itc_icon_image_get(void        *data,
    elm_icon_standard_set(ic, "image");
    elm_icon_thumb_set(ic, filename, NULL);
 
-   evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL,
-                                    1, 1);
+   evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
    return ic;
 }
 
 static Evas_Object *
-_itc_icon_file_get(void        *data __UNUSED__,
+_itc_icon_file_get(void *data __UNUSED__,
                    Evas_Object *obj,
-                   const char  *source)
+                   const char *source)
 {
    Evas_Object *ic;
 
@@ -300,8 +277,7 @@ _itc_icon_file_get(void        *data __UNUSED__,
    ic = elm_icon_add(obj);
    elm_icon_standard_set(ic, "file");
 
-   evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL,
-                                    1, 1);
+   evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
    return ic;
 }
 
@@ -314,253 +290,17 @@ _itc_state_get(void *data         __UNUSED__,
 }
 
 static void
-_itc_del(void            *data,
+_itc_del(void *data,
          Evas_Object *obj __UNUSED__)
 {
    eina_stringshare_del(data);
 }
 
-static void
-_expand_done(void            *data,
-             Evas_Object *obj __UNUSED__,
-             void            *event_info)
-{
-   Elm_Object_Item *it = event_info;
-   const char *path = elm_object_item_data_get(it);
-   _populate(data, path, it);
-}
-
-static void
-_contract_done(void *data       __UNUSED__,
-               Evas_Object *obj __UNUSED__,
-               void            *event_info)
-{
-   Elm_Object_Item *it = event_info;
-   elm_genlist_item_subitems_clear(it);
-}
-
-static void
-_expand_req(void *data       __UNUSED__,
-            Evas_Object *obj __UNUSED__,
-            void            *event_info)
-{
-   Elm_Object_Item *it = event_info;
-   elm_genlist_item_expanded_set(it, EINA_TRUE);
-}
-
-static void
-_contract_req(void *data       __UNUSED__,
-              Evas_Object *obj __UNUSED__,
-              void            *event_info)
-{
-   Elm_Object_Item *it = event_info;
-   elm_genlist_item_expanded_set(it, EINA_FALSE);
-}
-
-/***  PRIVATES  ***/
-static Eina_Bool
-_sel_do(void *data)
-{
-   struct sel_data *sd;
-   const char *path;
-   Widget_Data *wd;
-   const char *p;
-
-   sd = data;
-   wd = elm_widget_data_get(sd->fs);
-   path = sd->path;
-
-   if ((!wd->only_folder) && ecore_file_is_dir(path))
-     {
-        if (wd->expand && wd->mode == ELM_FILESELECTOR_LIST)
-          {
-             _do_anchors(sd->fs, path);
-             elm_object_text_set(wd->filename_entry, "");
-          }
-        else
-          {
-             /* keep a ref to path 'couse it will be destroyed by _populate */
-             p = eina_stringshare_add(path);
-             _populate(sd->fs, p, NULL);
-             eina_stringshare_del(p);
-          }
-        goto end;
-     }
-   else /* navigating through folders only or file is not a dir. */
-     {
-        char *s;
-        
-        if (wd->expand && wd->mode == ELM_FILESELECTOR_LIST)
-          _do_anchors(sd->fs, path);
-        else if (wd->only_folder)
-          {
-             /* keep a ref to path 'couse it will be destroyed by _populate */
-             p = eina_stringshare_add(path);
-             _populate(sd->fs, p, NULL);
-             eina_stringshare_del(p);
-          }
-        s = elm_entry_utf8_to_markup(ecore_file_file_get(path));
-        if (s)
-          {
-             elm_object_text_set(wd->filename_entry, s);
-             free(s);
-          }
-        else
-          elm_object_text_set(wd->filename_entry, "");
-     }
-
-   evas_object_smart_callback_call(sd->fs, SIG_SELECTED, (void *)path);
-
-end:
-   wd->sel_idler = NULL;
-   free(sd);
-   return ECORE_CALLBACK_CANCEL;
-}
-
-static void
-_sel(void            *data,
-     Evas_Object *obj __UNUSED__,
-     void            *event_info)
-{
-   struct sel_data *sd;
-   Widget_Data *wd;
-   void *old_sd;
-   char *dir;
-   //This event_info could be a list or gengrid item
-   Elm_Object_Item *it = event_info;
-
-   wd = elm_widget_data_get(data);
-   if (!wd) return;
-
-   sd = malloc(sizeof(*sd));
-   sd->fs = data;
-   sd->path = elm_object_item_data_get(it);
-
-   if (!sd->path)
-     {
-        eina_stringshare_replace(&wd->path, "");
-        goto end;
-     }
-
-   dir = wd->only_folder ? strdup(sd->path) : ecore_file_dir_get(sd->path);
-   if (dir)
-     {
-        eina_stringshare_replace(&wd->path, dir);
-        free(dir);
-     }
-   else
-     {
-        eina_stringshare_replace(&wd->path, "");
-     }
-
-end:
-   if (wd->sel_idler)
-     {
-        old_sd = ecore_idler_del(wd->sel_idler);
-        free(old_sd);
-     }
-   wd->sel_idler = ecore_idler_add(_sel_do, sd);
-}
-
-static void
-_up(void            *data,
-    Evas_Object *obj __UNUSED__,
-    void *event_info __UNUSED__)
-{
-   Evas_Object *fs = data;
-   char *parent;
-
-   Widget_Data *wd = elm_widget_data_get(fs);
-   if (!wd) return;
-   parent = ecore_file_dir_get(wd->path);
-   _populate(fs, parent, NULL);
-   free(parent);
-}
-
-static void
-_home(void            *data,
-      Evas_Object *obj __UNUSED__,
-      void *event_info __UNUSED__)
-{
-   Evas_Object *fs = data;
-   _populate(fs, getenv("HOME"), NULL);
-}
-
-static void
-_ok(void            *data,
-    Evas_Object *obj __UNUSED__,
-    void *event_info __UNUSED__)
-{
-   Evas_Object *fs = data;
-   evas_object_smart_callback_call(fs, SIG_DONE,
-                                   (void *)elm_fileselector_selected_get(fs));
-}
-
-static void
-_canc(void            *data,
-      Evas_Object *obj __UNUSED__,
-      void *event_info __UNUSED__)
-{
-   Evas_Object *fs = data;
-   evas_object_smart_callback_call(fs, SIG_DONE, NULL);
-}
-
-static void
-_anchor_clicked(void            *data,
-                Evas_Object *obj __UNUSED__,
-                void            *event_info)
-{
-   Evas_Object *fs = data;
-   Widget_Data *wd = elm_widget_data_get(fs);
-   Elm_Entry_Anchor_Info *info = event_info;
-   const char *p;
-   if (!wd) return;
-   // keep a ref to path 'couse it will be destroyed by _populate
-   p = eina_stringshare_add(info->name);
-   _populate(fs, p, NULL);
-   evas_object_smart_callback_call(data, SIG_SELECTED, (void *)p);
-   eina_stringshare_del(p);
-}
-
-static void
-_do_anchors(Evas_Object *obj,
-            const char  *path)
-{
-   Widget_Data *wd = elm_widget_data_get(obj);
-   char **tok, buf[PATH_MAX * 3], *s;
-   int i, j;
-   
-   if (!wd) return;
-   s = elm_entry_utf8_to_markup(path);
-   if (!s) return;
-   buf[0] = '\0';
-   tok = eina_str_split(s, "/", 0);
-   free(s);
-   eina_strlcat(buf, "<a href=/>root</a>", sizeof(buf));
-   for (i = 0; tok[i]; i++)
-     {
-        if ((!tok[i]) || (!tok[i][0])) continue;
-        eina_strlcat(buf, wd->path_separator, sizeof(buf));
-        eina_strlcat(buf, "<a href=", sizeof(buf));
-        for (j = 0; j <= i; j++)
-          {
-             if (strlen(tok[j]) < 1) continue;
-             eina_strlcat(buf, "/", sizeof(buf));
-             eina_strlcat(buf, tok[j], sizeof(buf));
-          }
-        eina_strlcat(buf, ">", sizeof(buf));
-        eina_strlcat(buf, tok[i], sizeof(buf));
-        eina_strlcat(buf, "</a>", sizeof(buf));
-     }
-   free(tok[0]);
-   free(tok);
-
-   elm_object_text_set(wd->path_entry, buf);
-}
-
 #ifdef HAVE_EIO
 static Eina_Bool
-_filter_cb(void *data __UNUSED__, Eio_File *handler, const Eina_File_Direct_Info *info)
+_ls_filter_cb(void *data __UNUSED__,
+              Eio_File *handler,
+              const Eina_File_Direct_Info *info)
 {
    const char *filename;
 
@@ -568,24 +308,32 @@ _filter_cb(void *data __UNUSED__, Eio_File *handler, const Eina_File_Direct_Info
      return EINA_FALSE;
 
    filename = eina_stringshare_add(info->path);
-   eio_file_associate_direct_add(handler, "filename", filename, EINA_FREE_CB(eina_stringshare_del));
+   eio_file_associate_direct_add
+     (handler, "filename", filename, EINA_FREE_CB(eina_stringshare_del));
 
    if (info->type == EINA_FILE_DIR)
      {
-        eio_file_associate_direct_add(handler, "type/grid", grid_itc[ELM_DIRECTORY], NULL);
-        eio_file_associate_direct_add(handler, "type/list", list_itc[ELM_DIRECTORY], NULL);
+        eio_file_associate_direct_add
+          (handler, "type/grid", grid_itc[ELM_DIRECTORY], NULL);
+        eio_file_associate_direct_add
+          (handler, "type/list", list_itc[ELM_DIRECTORY], NULL);
      }
    else
      {
-        if (evas_object_image_extension_can_load_get(info->path + info->name_start))
+        if (evas_object_image_extension_can_load_get
+              (info->path + info->name_start))
           {
-             eio_file_associate_direct_add(handler, "type/grid", grid_itc[ELM_FILE_IMAGE], NULL);
-             eio_file_associate_direct_add(handler, "type/list", list_itc[ELM_FILE_IMAGE], NULL);
+             eio_file_associate_direct_add
+               (handler, "type/grid", grid_itc[ELM_FILE_IMAGE], NULL);
+             eio_file_associate_direct_add
+               (handler, "type/list", list_itc[ELM_FILE_IMAGE], NULL);
           }
         else
           {
-             eio_file_associate_direct_add(handler, "type/grid", grid_itc[ELM_FILE_UNKNOW], NULL);
-             eio_file_associate_direct_add(handler, "type/list", list_itc[ELM_FILE_UNKNOW], NULL);
+             eio_file_associate_direct_add
+               (handler, "type/grid", grid_itc[ELM_FILE_UNKNOW], NULL);
+             eio_file_associate_direct_add
+               (handler, "type/list", list_itc[ELM_FILE_UNKNOW], NULL);
           }
      }
 
@@ -593,7 +341,8 @@ _filter_cb(void *data __UNUSED__, Eio_File *handler, const Eina_File_Direct_Info
 }
 
 static int
-_file_grid_cmp(const void *a, const void *b)
+_file_grid_cmp(const void *a,
+               const void *b)
 {
    const Elm_Object_Item *ga = a;
    const Elm_Object_Item *gb = b;
@@ -614,7 +363,8 @@ _file_grid_cmp(const void *a, const void *b)
 }
 
 static int
-_file_list_cmp(const void *a, const void *b)
+_file_list_cmp(const void *a,
+               const void *b)
 {
    const Elm_Object_Item *la = a;
    const Elm_Object_Item *lb = b;
@@ -635,244 +385,489 @@ _file_list_cmp(const void *a, const void *b)
 }
 
 static void
-_signal_first(Widget_Request *wr)
+_anchors_do(Evas_Object *obj,
+            const char *path)
+{
+   char **tok, buf[PATH_MAX * 3], *s;
+   int i, j;
+
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
+
+   s = elm_entry_utf8_to_markup(path);
+   if (!s) return;
+
+   buf[0] = '\0';
+   tok = eina_str_split(s, "/", 0);
+   free(s);
+
+   eina_strlcat(buf, "<a href=/>root</a>", sizeof(buf));
+   for (i = 0; tok[i]; i++)
+     {
+        if ((!tok[i]) || (!tok[i][0])) continue;
+        eina_strlcat(buf, sd->path_separator, sizeof(buf));
+        eina_strlcat(buf, "<a href=", sizeof(buf));
+        for (j = 0; j <= i; j++)
+          {
+             if (strlen(tok[j]) < 1) continue;
+             eina_strlcat(buf, "/", sizeof(buf));
+             eina_strlcat(buf, tok[j], sizeof(buf));
+          }
+        eina_strlcat(buf, ">", sizeof(buf));
+        eina_strlcat(buf, tok[i], sizeof(buf));
+        eina_strlcat(buf, "</a>", sizeof(buf));
+     }
+   free(tok[0]);
+   free(tok);
+
+   elm_object_text_set(sd->path_entry, buf);
+}
+
+static void
+_signal_first(Listing_Request *lreq)
 {
-   if (!wr->first) return ;
-   evas_object_smart_callback_call(wr->obj, SIG_DIRECTORY_OPEN, (void *)wr->path);
-   if (!wr->parent)
+   if (!lreq->first) return;
+
+   evas_object_smart_callback_call
+     (lreq->obj, SIG_DIRECTORY_OPEN, (void *)lreq->path);
+
+   if (!lreq->parent_it)
      {
-        elm_genlist_clear(wr->wd->files_list);
-        elm_gengrid_clear(wr->wd->files_grid);
-        eina_stringshare_replace(&wr->wd->path, wr->path);
-        _do_anchors(wr->obj, wr->path);
+        elm_genlist_clear(lreq->sd->files_list);
+        elm_gengrid_clear(lreq->sd->files_grid);
+        eina_stringshare_replace(&lreq->sd->path, lreq->path);
+        _anchors_do(lreq->obj, lreq->path);
      }
 
-   if (wr->wd->filename_entry) elm_object_text_set(wr->wd->filename_entry, "");
+   if (lreq->sd->filename_entry)
+     elm_object_text_set(lreq->sd->filename_entry, "");
 
-   wr->first = EINA_FALSE;
+   lreq->first = EINA_FALSE;
 }
 
 static void
-_main_cb(void *data, Eio_File *handler, const Eina_File_Direct_Info *info __UNUSED__)
+_ls_main_cb(void *data,
+            Eio_File *handler,
+            const Eina_File_Direct_Info *info __UNUSED__)
 {
-   Widget_Request *wr = data;
+   Listing_Request *lreq = data;
 
-   if (eio_file_check(handler))
-     return ;
-   if (!wr->wd->files_list || !wr->wd->files_grid || wr->wd->current != handler)
+   if (eio_file_check(handler)) return;
+
+   if (!lreq->sd->files_list || !lreq->sd->files_grid
+       || lreq->sd->current != handler)
      {
         eio_file_cancel(handler);
-        return ;
+        return;
      }
 
-   _signal_first(wr);
+   _signal_first(lreq);
 
-   if (wr->wd->mode == ELM_FILESELECTOR_LIST)
+   if (lreq->sd->mode == ELM_FILESELECTOR_LIST)
      {
-        Eina_Bool is_dir = (eio_file_associate_find(handler, "type/list") == list_itc[ELM_DIRECTORY]);
-
-        elm_genlist_item_sorted_insert(wr->wd->files_list, eio_file_associate_find(handler, "type/list"),
-                                       eina_stringshare_ref(eio_file_associate_find(handler, "filename")),
-                                       wr->parent, wr->wd->expand && is_dir ? ELM_GENLIST_ITEM_TREE : ELM_GENLIST_ITEM_NONE,
-                                       _file_list_cmp, NULL, NULL);
+        Eina_Bool is_dir = (eio_file_associate_find(handler, "type/list")
+                            == list_itc[ELM_DIRECTORY]);
+
+        elm_genlist_item_sorted_insert
+          (lreq->sd->files_list, eio_file_associate_find(handler, "type/list"),
+          eina_stringshare_ref(eio_file_associate_find
+                                 (handler, "filename")),
+          lreq->parent_it, lreq->sd->expand && is_dir ? ELM_GENLIST_ITEM_TREE
+          : ELM_GENLIST_ITEM_NONE, _file_list_cmp, NULL, NULL);
      }
-   else if (wr->wd->mode == ELM_FILESELECTOR_GRID)
-     elm_gengrid_item_sorted_insert(wr->wd->files_grid, eio_file_associate_find(handler, "type/grid"),
-                                           eina_stringshare_ref(eio_file_associate_find(handler, "filename")),
-                                           _file_grid_cmp, NULL, NULL);
+   else if (lreq->sd->mode == ELM_FILESELECTOR_GRID)
+     elm_gengrid_item_sorted_insert
+       (lreq->sd->files_grid, eio_file_associate_find(handler, "type/grid"),
+       eina_stringshare_ref(eio_file_associate_find(handler, "filename")),
+       _file_grid_cmp, NULL, NULL);
 }
 
 static void
-_widget_request_cleanup(Widget_Request *wr)
+_listing_request_cleanup(Listing_Request *lreq)
 {
-   EINA_REFCOUNT_UNREF(wr->wd)
-     _widget_data_free(wr->wd);
+   EINA_REFCOUNT_UNREF(lreq->sd) _elm_fileselector_smart_del_do(lreq->sd);
 
-   eina_stringshare_del(wr->path);
-   free(wr);
+   eina_stringshare_del(lreq->path);
+   free(lreq);
 }
 
 static void
-_done_cb(void *data, Eio_File *handler __UNUSED__)
+_ls_done_cb(void *data, Eio_File *handler __UNUSED__)
 {
-   Widget_Request *wr = data;
+   Listing_Request *lreq = data;
 
-   _signal_first(wr);
+   _signal_first(lreq);
 
-   wr->wd->current = NULL;
-   _widget_request_cleanup(wr);
+   lreq->sd->current = NULL;
+   _listing_request_cleanup(lreq);
 }
 
 static void
-_error_cb(void *data, Eio_File *handler, int error __UNUSED__)
+_ls_error_cb(void *data, Eio_File *handler, int error __UNUSED__)
 {
-   Widget_Request *wr = data;
+   Listing_Request *lreq = data;
 
-   if (wr->wd->current == handler)
-     wr->wd->current = NULL;
-   _widget_request_cleanup(wr);
+   if (lreq->sd->current == handler)
+     lreq->sd->current = NULL;
+   _listing_request_cleanup(lreq);
 }
 
 #endif
 
 static void
-_populate(Evas_Object      *obj,
-          const char       *path,
-          Elm_Object_Item  *parent)
+_populate(Evas_Object *obj,
+          const char *path,
+          Elm_Object_Item *parent_it)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
+
 #ifdef HAVE_EIO
-   Widget_Request *wr;
+   Listing_Request *lreq;
 #else
+   Eina_List *files = NULL, *dirs = NULL;
    Eina_File_Direct_Info *file;
    Eina_Iterator *it;
-   const char *real;
-   Eina_List *files = NULL, *dirs = NULL;
+   const char *entry;
 #endif
 
-   if (!wd) return;
-#ifndef HAVE_EIO
-   if (!ecore_file_is_dir(path)) return ;
+#ifndef HAVE_EIO /* synchronous listing path */
+   if (!ecore_file_is_dir(path)) return;
+
    it = eina_file_stat_ls(path);
-   if (!it) return ;
+   if (!it) return;
+
    evas_object_smart_callback_call(obj, SIG_DIRECTORY_OPEN, (void *)path);
-   if (!parent)
+   if (!parent_it)
      {
-        elm_genlist_clear(wd->files_list);
-        elm_gengrid_clear(wd->files_grid);
-        eina_stringshare_replace(&wd->path, path);
-        _do_anchors(obj, path);
+        elm_genlist_clear(sd->files_list);
+        elm_gengrid_clear(sd->files_grid);
+        eina_stringshare_replace(&sd->path, path);
+        _anchors_do(obj, path);
      }
 
-   if (wd->filename_entry) elm_object_text_set(wd->filename_entry, "");
-   EINA_ITERATOR_FOREACH(it, file)
+   if (sd->filename_entry) elm_object_text_set(sd->filename_entry, "");
+   EINA_ITERATOR_FOREACH (it, file)
      {
         const char *filename;
 
-        if (file->path[file->name_start] == '.')
-          continue ;
+        if (file->path[file->name_start] == '.') continue;
 
         filename = eina_stringshare_add(file->path);
         if (file->type == EINA_FILE_DIR)
           dirs = eina_list_append(dirs, filename);
-        else if (!wd->only_folder)
+        else if (!sd->only_folder)
           files = eina_list_append(files, filename);
      }
    eina_iterator_free(it);
 
-   files = eina_list_sort(files, eina_list_count(files),
-                          EINA_COMPARE_CB(strcoll));
-   dirs = eina_list_sort(dirs, eina_list_count(dirs), EINA_COMPARE_CB(strcoll));
-   EINA_LIST_FREE(dirs, real)
+   files = eina_list_sort
+       (files, eina_list_count(files), EINA_COMPARE_CB(strcoll));
+
+   dirs = eina_list_sort
+       (dirs, eina_list_count(dirs), EINA_COMPARE_CB(strcoll));
+   EINA_LIST_FREE (dirs, entry)
      {
-        if (wd->mode == ELM_FILESELECTOR_LIST)
-          elm_genlist_item_append(wd->files_list, list_itc[ELM_DIRECTORY],
-                                  real, /* item data */
-                                  parent,
-                                  wd->expand ? ELM_GENLIST_ITEM_TREE :
+        if (sd->mode == ELM_FILESELECTOR_LIST)
+          elm_genlist_item_append(sd->files_list, list_itc[ELM_DIRECTORY],
+                                  entry, /* item data */
+                                  parent_it,
+                                  sd->expand ? ELM_GENLIST_ITEM_TREE :
                                   ELM_GENLIST_ITEM_NONE,
                                   NULL, NULL);
-        else if (wd->mode == ELM_FILESELECTOR_GRID)
-          elm_gengrid_item_append(wd->files_grid, grid_itc[ELM_DIRECTORY],
-                                  real, /* item data */
+        else if (sd->mode == ELM_FILESELECTOR_GRID)
+          elm_gengrid_item_append(sd->files_grid, grid_itc[ELM_DIRECTORY],
+                                  entry, /* item data */
                                   NULL, NULL);
      }
 
-   EINA_LIST_FREE(files, real)
+   EINA_LIST_FREE (files, entry)
      {
-        Elm_Fileselector_Type type = evas_object_image_extension_can_load_fast_get(real) ?
+        Elm_Fileselector_Type type =
+          evas_object_image_extension_can_load_fast_get(entry) ?
           ELM_FILE_IMAGE : ELM_FILE_UNKNOW;
 
-        if (wd->mode == ELM_FILESELECTOR_LIST)
-          elm_genlist_item_append(wd->files_list, list_itc[type],
-                                  real, /* item data */
-                                  parent, ELM_GENLIST_ITEM_NONE,
+        if (sd->mode == ELM_FILESELECTOR_LIST)
+          elm_genlist_item_append(sd->files_list, list_itc[type],
+                                  entry, /* item data */
+                                  parent_it, ELM_GENLIST_ITEM_NONE,
                                   NULL, NULL);
-        else if (wd->mode == ELM_FILESELECTOR_GRID)
-          elm_gengrid_item_append(wd->files_grid, grid_itc[type],
-                                  real, /* item data */
+        else if (sd->mode == ELM_FILESELECTOR_GRID)
+          elm_gengrid_item_append(sd->files_grid, grid_itc[type],
+                                  entry, /* item data */
                                   NULL, NULL);
      }
-#else
-   if (wd->expand && wd->current) return ;
-   if (wd->current)
-     eio_file_cancel(wd->current);
-   wr = malloc(sizeof (Widget_Request));
-   if (!wr) return ;
-   wr->wd = wd;
-   EINA_REFCOUNT_REF(wr->wd);
-   wr->parent = parent; /* FIXME: should we refcount the parent ? */
-   wr->obj = obj;
-   wr->path = eina_stringshare_add(path);
-   wr->first = EINA_TRUE;
-
-   wd->current = eio_file_stat_ls(path,
-                                  _filter_cb,
-                                  _main_cb,
-                                  _done_cb,
-                                  _error_cb,
-                                  wr);
+
+#else /* asynchronous listing path */
+   if (sd->expand && sd->current) return;
+
+   if (sd->current) eio_file_cancel(sd->current);
+
+   lreq = malloc(sizeof (Listing_Request));
+   if (!lreq) return;
+
+   lreq->sd = sd;
+   EINA_REFCOUNT_REF(lreq->sd);
+
+   lreq->parent_it = parent_it; /* FIXME: should we refcount the parent_it ? */
+   lreq->obj = obj;
+   lreq->path = eina_stringshare_add(path);
+   lreq->first = EINA_TRUE;
+
+   sd->current = eio_file_stat_ls(path, _ls_filter_cb, _ls_main_cb,
+                                  _ls_done_cb, _ls_error_cb, lreq);
 #endif
 }
 
-/***  API  ***/
+static void
+_on_list_expanded(void *data,
+                  Evas_Object *obj __UNUSED__,
+                  void *event_info)
+{
+   Elm_Object_Item *it = event_info;
+   const char *path = elm_object_item_data_get(it);
+
+   _populate(data, path, it);
+}
 
-EAPI Evas_Object *
-elm_fileselector_add(Evas_Object *parent)
+static void
+_on_list_contracted(void *data       __UNUSED__,
+                    Evas_Object *obj __UNUSED__,
+                    void *event_info)
 {
-   Evas *e;
-   Evas_Object *obj, *ic, *bt, *li, *en, *grid;
-   Widget_Data *wd;
+   Elm_Object_Item *it = event_info;
+
+   elm_genlist_item_subitems_clear(it);
+}
+
+static void
+_on_list_expand_req(void *data       __UNUSED__,
+                    Evas_Object *obj __UNUSED__,
+                    void *event_info)
+{
+   Elm_Object_Item *it = event_info;
+
+   elm_genlist_item_expanded_set(it, EINA_TRUE);
+}
+
+static void
+_on_list_contract_req(void *data       __UNUSED__,
+                      Evas_Object *obj __UNUSED__,
+                      void *event_info)
+{
+   Elm_Object_Item *it = event_info;
+
+   elm_genlist_item_expanded_set(it, EINA_FALSE);
+}
+
+static Eina_Bool
+_sel_do(void *data)
+{
+   struct sel_data *sdata = data;
+   const char *path;
+   const char *p;
+
+   ELM_FILESELECTOR_DATA_GET(sdata->fs, sd);
+   path = sdata->path;
+
+   if ((!sd->only_folder) && ecore_file_is_dir(path))
+     {
+        if (sd->expand && sd->mode == ELM_FILESELECTOR_LIST)
+          {
+             _anchors_do(sdata->fs, path);
+             elm_object_text_set(sd->filename_entry, "");
+          }
+        else
+          {
+             /* keep a ref to path 'couse it will be destroyed by _populate */
+             p = eina_stringshare_add(path);
+             _populate(sdata->fs, p, NULL);
+             eina_stringshare_del(p);
+          }
+        goto end;
+     }
+   else /* navigating through folders only or file is not a dir. */
+     {
+        char *s;
+
+        if (sd->expand && sd->mode == ELM_FILESELECTOR_LIST)
+          _anchors_do(sdata->fs, path);
+        else if (sd->only_folder)
+          {
+             /* keep a ref to path 'couse it will be destroyed by _populate */
+             p = eina_stringshare_add(path);
+             _populate(sdata->fs, p, NULL);
+             eina_stringshare_del(p);
+          }
+
+        s = elm_entry_utf8_to_markup(ecore_file_file_get(path));
+        if (s)
+          {
+             elm_object_text_set(sd->filename_entry, s);
+             free(s);
+          }
+        else elm_object_text_set(sd->filename_entry, "");
+     }
+
+   evas_object_smart_callback_call(sdata->fs, SIG_SELECTED, (void *)path);
+
+end:
+   sd->sel_idler = NULL;
+   free(sdata);
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_on_item_selected(void *data,
+                  Evas_Object *obj __UNUSED__,
+                  void *event_info)
+{
+   //This event_info could be a list or gengrid item
+   Elm_Object_Item *it = event_info;
+   struct sel_data *sdata;
+   void *old_sd;
+   char *dir;
+
+   ELM_FILESELECTOR_DATA_GET(data, sd);
+
+   sdata = malloc(sizeof(*sdata));
+   sdata->fs = data;
+   sdata->path = elm_object_item_data_get(it);
+
+   if (!sdata->path)
+     {
+        eina_stringshare_replace(&sd->path, "");
+        goto end;
+     }
+
+   dir = sd->only_folder ? strdup(sdata->path) :
+     ecore_file_dir_get(sdata->path);
+   if (dir)
+     {
+        eina_stringshare_replace(&sd->path, dir);
+        free(dir);
+     }
+   else
+     {
+        eina_stringshare_replace(&sd->path, "");
+     }
+
+end:
+   if (sd->sel_idler)
+     {
+        old_sd = ecore_idler_del(sd->sel_idler);
+        free(old_sd);
+     }
+   sd->sel_idler = ecore_idler_add(_sel_do, sdata);
+}
+
+static void
+_on_dir_up(void *data,
+           Evas_Object *obj __UNUSED__,
+           void *event_info __UNUSED__)
+{
+   Evas_Object *fs = data;
+   char *parent;
+
+   ELM_FILESELECTOR_DATA_GET(fs, sd);
+
+   parent = ecore_file_dir_get(sd->path);
+   _populate(fs, parent, NULL);
+   free(parent);
+}
+
+static void
+_home(void *data,
+      Evas_Object *obj __UNUSED__,
+      void *event_info __UNUSED__)
+{
+   Evas_Object *fs = data;
+
+   _populate(fs, getenv("HOME"), NULL);
+}
+
+static void
+_ok(void *data,
+    Evas_Object *obj __UNUSED__,
+    void *event_info __UNUSED__)
+{
+   Evas_Object *fs = data;
+
+   evas_object_smart_callback_call
+     (fs, SIG_DONE, (void *)elm_fileselector_selected_get(fs));
+}
+
+static void
+_canc(void *data,
+      Evas_Object *obj __UNUSED__,
+      void *event_info __UNUSED__)
+{
+   Evas_Object *fs = data;
+
+   evas_object_smart_callback_call(fs, SIG_DONE, NULL);
+}
+
+static void
+_anchor_clicked(void *data,
+                Evas_Object *obj __UNUSED__,
+                void *event_info)
+{
+   Elm_Entry_Anchor_Info *info = event_info;
+   Evas_Object *fs = data;
+   const char *p;
+
+   // keep a ref to path 'couse it will be destroyed by _populate
+   p = eina_stringshare_add(info->name);
+   _populate(fs, p, NULL);
+   evas_object_smart_callback_call(data, SIG_SELECTED, (void *)p);
+   eina_stringshare_del(p);
+}
+
+static void
+_elm_fileselector_smart_add(Evas_Object *obj)
+{
+   Evas_Object *ic, *bt, *li, *en, *grid;
    unsigned int i;
    int s;
 
-   ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
+   EVAS_SMART_DATA_ALLOC(obj, Elm_Fileselector_Smart_Data);
+   EINA_REFCOUNT_INIT(priv);
 
-   EINA_REFCOUNT_INIT(wd);
+   ELM_WIDGET_CLASS(_elm_fileselector_parent_sc)->base.add(obj);
 
-   ELM_SET_WIDTYPE(widtype, "fileselector");
-   elm_widget_type_set(obj, "fileselector");
-   elm_widget_sub_object_add(parent, obj);
-   elm_widget_data_set(obj, wd);
-   elm_widget_del_hook_set(obj, _del_hook);
-   elm_widget_theme_hook_set(obj, _theme_hook);
    elm_widget_can_focus_set(obj, EINA_FALSE);
 
-   wd->expand = !!_elm_config->fileselector_expand_enable;
+   priv->expand = !!_elm_config->fileselector_expand_enable;
 
-   wd->edje = edje_object_add(e);
-   _elm_theme_object_set(obj, wd->edje, "fileselector", "base", "default");
-   elm_widget_resize_object_set(obj, wd->edje);
+   elm_layout_theme_set
+     (obj, "fileselector", "base", elm_widget_style_get(obj));
 
    // up btn
-   ic = elm_icon_add(parent);
+   ic = elm_icon_add(obj);
    elm_icon_standard_set(ic, "arrow_up");
    evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
-   bt = elm_button_add(parent);
+   bt = elm_button_add(obj);
    elm_widget_mirrored_automatic_set(bt, EINA_FALSE);
    elm_object_part_content_set(bt, "icon", ic);
    elm_object_domain_translatable_text_set(bt, PACKAGE, N_("Up"));
    evas_object_size_hint_align_set(bt, 0.0, 0.0);
-
-   evas_object_smart_callback_add(bt, "clicked", _up, obj);
+   evas_object_smart_callback_add(bt, "clicked", _on_dir_up, obj);
 
    elm_widget_sub_object_add(obj, bt);
-   wd->up_button = bt;
+
+   priv->up_button = bt;
 
    // home btn
-   ic = elm_icon_add(parent);
+   ic = elm_icon_add(obj);
    elm_icon_standard_set(ic, "home");
    evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
-   bt = elm_button_add(parent);
+   bt = elm_button_add(obj);
    elm_widget_mirrored_automatic_set(bt, EINA_FALSE);
    elm_object_part_content_set(bt, "icon", ic);
    elm_object_domain_translatable_text_set(bt, PACKAGE, N_("Home"));
    evas_object_size_hint_align_set(bt, 0.0, 0.0);
-
    evas_object_smart_callback_add(bt, "clicked", _home, obj);
 
    elm_widget_sub_object_add(obj, bt);
-   wd->home_button = bt;
+   priv->home_button = bt;
 
    for (i = 0; i < ELM_FILE_LAST; ++i)
      {
@@ -880,8 +875,10 @@ elm_fileselector_add(Evas_Object *parent)
         grid_itc[i] = elm_gengrid_item_class_new();
 
         list_itc[i]->item_style = "default";
-        list_itc[i]->func.text_get = grid_itc[i]->func.text_get = _itc_text_get;
-        list_itc[i]->func.state_get = grid_itc[i]->func.state_get = _itc_state_get;
+        list_itc[i]->func.text_get = grid_itc[i]->func.text_get =
+            _itc_text_get;
+        list_itc[i]->func.state_get = grid_itc[i]->func.state_get =
+            _itc_state_get;
         list_itc[i]->func.del = grid_itc[i]->func.del = _itc_del;
      }
 
@@ -892,37 +889,39 @@ elm_fileselector_add(Evas_Object *parent)
    list_itc[ELM_FILE_UNKNOW]->func.content_get =
      grid_itc[ELM_FILE_UNKNOW]->func.content_get = _itc_icon_file_get;
 
-   li = elm_genlist_add(parent);
+   li = elm_genlist_add(obj);
    elm_widget_mirrored_automatic_set(li, EINA_FALSE);
    evas_object_size_hint_align_set(li, EVAS_HINT_FILL, EVAS_HINT_FILL);
    evas_object_size_hint_weight_set(li, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    evas_object_size_hint_min_set(li, 100, 100);
 
-   grid = elm_gengrid_add(parent);
+   grid = elm_gengrid_add(obj);
    elm_widget_mirrored_automatic_set(grid, EINA_FALSE);
    evas_object_size_hint_align_set(grid, EVAS_HINT_FILL, EVAS_HINT_FILL);
    evas_object_size_hint_weight_set(grid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
 
    // XXX: will fail for dynamic finger size changing
-   s = _elm_config->finger_size * 2;
+   s = elm_config_finger_size_get() * 2;
    elm_gengrid_item_size_set(grid, s, s);
    elm_gengrid_align_set(grid, 0.0, 0.0);
 
-   evas_object_smart_callback_add(li, "selected", _sel, obj);
-   evas_object_smart_callback_add(li, "expand,request", _expand_req, obj);
-   evas_object_smart_callback_add(li, "contract,request", _contract_req, obj);
-   evas_object_smart_callback_add(li, "expanded", _expand_done, obj);
-   evas_object_smart_callback_add(li, "contracted", _contract_done, obj);
+   evas_object_smart_callback_add(li, "selected", _on_item_selected, obj);
+   evas_object_smart_callback_add
+     (li, "expand,request", _on_list_expand_req, obj);
+   evas_object_smart_callback_add
+     (li, "contract,request", _on_list_contract_req, obj);
+   evas_object_smart_callback_add(li, "expanded", _on_list_expanded, obj);
+   evas_object_smart_callback_add(li, "contracted", _on_list_contracted, obj);
 
-   evas_object_smart_callback_add(grid, "selected", _sel, obj);
+   evas_object_smart_callback_add(grid, "selected", _on_item_selected, obj);
 
    elm_widget_sub_object_add(obj, li);
    elm_widget_sub_object_add(obj, grid);
-   wd->files_list = li;
-   wd->files_grid = grid;
+   priv->files_list = li;
+   priv->files_grid = grid;
 
    // path entry
-   en = elm_entry_add(parent);
+   en = elm_entry_add(obj);
    elm_entry_scrollable_set(en, EINA_TRUE);
    elm_widget_mirrored_automatic_set(en, EINA_FALSE);
    elm_entry_editable_set(en, EINA_FALSE);
@@ -934,10 +933,10 @@ elm_fileselector_add(Evas_Object *parent)
    evas_object_smart_callback_add(en, "anchor,clicked", _anchor_clicked, obj);
 
    elm_widget_sub_object_add(obj, en);
-   wd->path_entry = en;
+   priv->path_entry = en;
 
    // filename entry
-   en = elm_entry_add(parent);
+   en = elm_entry_add(obj);
    elm_entry_scrollable_set(en, EINA_TRUE);
    elm_widget_mirrored_automatic_set(en, EINA_FALSE);
    elm_entry_editable_set(en, EINA_TRUE);
@@ -947,71 +946,124 @@ elm_fileselector_add(Evas_Object *parent)
    evas_object_size_hint_align_set(en, EVAS_HINT_FILL, EVAS_HINT_FILL);
 
    elm_widget_sub_object_add(obj, en);
-   wd->filename_entry = en;
+   priv->filename_entry = en;
 
    elm_fileselector_buttons_ok_cancel_set(obj, EINA_TRUE);
    elm_fileselector_is_save_set(obj, EINA_FALSE);
 
-   _theme_hook(obj);
+   _elm_fileselector_smart_theme(obj);
+}
+
+static void
+_elm_fileselector_smart_del(Evas_Object *obj)
+{
+   int i;
+
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
+
+   for (i = 0; i < ELM_FILE_LAST; ++i)
+     {
+        elm_genlist_item_class_free(list_itc[i]);
+        elm_gengrid_item_class_free(grid_itc[i]);
+     }
+
+#ifdef HAVE_EIO
+   if (sd->current) eio_file_cancel(sd->current);
+#endif
+
+   sd->files_list = NULL;
+   sd->files_grid = NULL;
+
+   /* this one matching EINA_REFCOUNT_INIT() */
+   EINA_REFCOUNT_UNREF(sd) _elm_fileselector_smart_del_do(sd);
+}
+
+static void
+_elm_fileselector_smart_set_user(Elm_Layout_Smart_Class *sc)
+{
+   ELM_WIDGET_CLASS(sc)->base.add = _elm_fileselector_smart_add;
+   ELM_WIDGET_CLASS(sc)->base.del = _elm_fileselector_smart_del;
+
+   ELM_WIDGET_CLASS(sc)->theme = _elm_fileselector_smart_theme;
+
+   /* not a 'focus chain manager' */
+   ELM_WIDGET_CLASS(sc)->focus_next = NULL;
+   ELM_WIDGET_CLASS(sc)->focus_direction = NULL;
+
+   sc->sizing_eval = _elm_fileselector_smart_sizing_eval;
+}
+
+EAPI Evas_Object *
+elm_fileselector_add(Evas_Object *parent)
+{
+   Evas *e;
+   Evas_Object *obj;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
+
+   e = evas_object_evas_get(parent);
+   if (!e) return NULL;
+
+   obj = evas_object_smart_add(e, _elm_fileselector_smart_class_new());
+
+   if (!elm_widget_sub_object_add(parent, obj))
+     ERR("could not add %p as sub object of %p", obj, parent);
 
-   evas_object_smart_callbacks_descriptions_set(obj, _signals);
    return obj;
 }
 
 EAPI void
 elm_fileselector_is_save_set(Evas_Object *obj,
-                             Eina_Bool    is_save)
+                             Eina_Bool is_save)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
+   ELM_FILESELECTOR_CHECK(obj);
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
 
-   elm_object_disabled_set(wd->filename_entry, !is_save);
+   elm_object_disabled_set(sd->filename_entry, !is_save);
 
-   if (is_save)
-     edje_object_signal_emit(wd->edje, "elm,state,save,on", "elm");
-   else
-     edje_object_signal_emit(wd->edje, "elm,state,save,off", "elm");
+   if (is_save) elm_layout_signal_emit(obj, "elm,state,save,on", "elm");
+   else elm_layout_signal_emit(obj, "elm,state,save,off", "elm");
 }
 
 EAPI Eina_Bool
 elm_fileselector_is_save_get(const Evas_Object *obj)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return EINA_FALSE;
-   return !elm_object_disabled_get(wd->filename_entry);
+   ELM_FILESELECTOR_CHECK(obj) EINA_FALSE;
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
+
+   return !elm_object_disabled_get(sd->filename_entry);
 }
 
 EAPI void
 elm_fileselector_folder_only_set(Evas_Object *obj,
-                                 Eina_Bool    only)
+                                 Eina_Bool only)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   if (wd->only_folder == only) return;
-   wd->only_folder = !!only;
-   if (wd->path) _populate(obj, wd->path, NULL);
+   ELM_FILESELECTOR_CHECK(obj);
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
+
+   if (sd->only_folder == only) return;
+
+   sd->only_folder = !!only;
+   if (sd->path) _populate(obj, sd->path, NULL);
 }
 
 EAPI Eina_Bool
 elm_fileselector_folder_only_get(const Evas_Object *obj)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return EINA_FALSE;
-   return wd->only_folder;
+   ELM_FILESELECTOR_CHECK(obj) EINA_FALSE;
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
+
+   return sd->only_folder;
 }
 
 EAPI void
 elm_fileselector_buttons_ok_cancel_set(Evas_Object *obj,
-                                       Eina_Bool    visible)
+                                       Eina_Bool visible)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
    Evas_Object *bt;
-   if (!wd) return;
+
+   ELM_FILESELECTOR_CHECK(obj);
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
 
    if (visible)
      {
@@ -1023,7 +1075,7 @@ elm_fileselector_buttons_ok_cancel_set(Evas_Object *obj,
         evas_object_smart_callback_add(bt, "clicked", _canc, obj);
 
         elm_widget_sub_object_add(obj, bt);
-        wd->cancel_button = bt;
+        sd->cancel_button = bt;
 
         // ok btn
         bt = elm_button_add(obj);
@@ -1033,58 +1085,57 @@ elm_fileselector_buttons_ok_cancel_set(Evas_Object *obj,
         evas_object_smart_callback_add(bt, "clicked", _ok, obj);
 
         elm_widget_sub_object_add(obj, bt);
-        wd->ok_button = bt;
+        sd->ok_button = bt;
 
-        _theme_hook(obj);
+        _elm_fileselector_smart_theme(obj);
      }
    else
      {
-        evas_object_del(wd->cancel_button);
-        wd->cancel_button = NULL;
-        evas_object_del(wd->ok_button);
-        wd->ok_button = NULL;
+        evas_object_del(sd->cancel_button);
+        sd->cancel_button = NULL;
+        evas_object_del(sd->ok_button);
+        sd->ok_button = NULL;
      }
 }
 
 EAPI Eina_Bool
 elm_fileselector_buttons_ok_cancel_get(const Evas_Object *obj)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return EINA_FALSE;
-   return wd->ok_button ? EINA_TRUE : EINA_FALSE;
+   ELM_FILESELECTOR_CHECK(obj) EINA_FALSE;
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
+
+   return sd->ok_button ? EINA_TRUE : EINA_FALSE;
 }
 
 EAPI void
 elm_fileselector_expandable_set(Evas_Object *obj,
-                                Eina_Bool    expand)
+                                Eina_Bool expand)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd;
+   ELM_FILESELECTOR_CHECK(obj);
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
 
-   wd = elm_widget_data_get(obj);
-   if (!wd) return;
+   sd->expand = !!expand;
 
-   wd->expand = !!expand;
-
-   if (wd->path) _populate(obj, wd->path, NULL);
+   if (sd->path) _populate(obj, sd->path, NULL);
 }
 
 EAPI Eina_Bool
 elm_fileselector_expandable_get(const Evas_Object *obj)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return EINA_FALSE;
-   return wd->expand;
+   ELM_FILESELECTOR_CHECK(obj) EINA_FALSE;
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
+
+   return sd->expand;
 }
 
 EAPI void
 elm_fileselector_path_set(Evas_Object *obj,
-                          const char  *_path)
+                          const char *_path)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
    char *path;
+
+   ELM_FILESELECTOR_CHECK(obj);
+
    path = ecore_file_realpath(_path);
    _populate(obj, path, NULL);
    free(path);
@@ -1093,79 +1144,59 @@ elm_fileselector_path_set(Evas_Object *obj,
 EAPI const char *
 elm_fileselector_path_get(const Evas_Object *obj)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype) NULL;
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return NULL;
-   return wd->path;
+   ELM_FILESELECTOR_CHECK(obj) NULL;
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
+
+   return sd->path;
 }
 
 EAPI void
-elm_fileselector_mode_set(Evas_Object          *obj,
+elm_fileselector_mode_set(Evas_Object *obj,
                           Elm_Fileselector_Mode mode)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
+   ELM_FILESELECTOR_CHECK(obj);
+
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
 
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
+   if (mode == sd->mode) return;
 
-   if (mode == wd->mode) return;
+   evas_object_hide(elm_layout_content_unset(obj, "elm.swallow.files"));
 
    if (mode == ELM_FILESELECTOR_LIST)
-     {
-        if (edje_object_part_swallow(wd->edje, "elm.swallow.files",
-                                     wd->files_list))
-          {
-             evas_object_show(wd->files_list);
-             evas_object_hide(wd->files_grid);
-          }
-        else
-          evas_object_hide(wd->files_list);
-     }
-   else
-     {
-        if (edje_object_part_swallow(wd->edje, "elm.swallow.files",
-                                     wd->files_grid))
-          {
-             evas_object_show(wd->files_grid);
-             evas_object_hide(wd->files_list);
-          }
-        else
-          evas_object_hide(wd->files_grid);
-     }
+     elm_layout_content_set(obj, "elm.swallow.files", sd->files_list);
+   else elm_layout_content_set(obj, "elm.swallow.files", sd->files_grid);
 
-   wd->mode = mode;
+   sd->mode = mode;
 
-   _populate(obj, wd->path, NULL);
+   _populate(obj, sd->path, NULL);
 }
 
 EAPI Elm_Fileselector_Mode
 elm_fileselector_mode_get(const Evas_Object *obj)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype) ELM_FILESELECTOR_LAST;
-
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return ELM_FILESELECTOR_LAST;
+   ELM_FILESELECTOR_CHECK(obj) ELM_FILESELECTOR_LAST;
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
 
-   return wd->mode;
+   return sd->mode;
 }
 
 EAPI const char *
 elm_fileselector_selected_get(const Evas_Object *obj)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype) NULL;
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return NULL;
+   ELM_FILESELECTOR_CHECK(obj) NULL;
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
 
-   if (!wd->path) return NULL;
-   
-   if (wd->filename_entry)
+   if (!sd->path) return NULL;
+
+   if (sd->filename_entry)
      {
-        const char *name;
         char buf[PATH_MAX];
+        const char *name;
         char *dir, *s;
 
-        dir = wd->only_folder ? ecore_file_dir_get(wd->path) : strdup(wd->path);
-        name = elm_object_text_get(wd->filename_entry);
+        dir = sd->only_folder ? ecore_file_dir_get(sd->path)
+          : strdup(sd->path);
+        name = elm_object_text_get(sd->filename_entry);
         if (name)
           {
              s = elm_entry_markup_to_utf8(name);
@@ -1174,49 +1205,47 @@ elm_fileselector_selected_get(const Evas_Object *obj)
                   snprintf(buf, sizeof(buf), "%s/%s", dir, s);
                   free(s);
                }
-             else
-               snprintf(buf, sizeof(buf), "%s", dir);
-          }
-        else
-          {
-             snprintf(buf, sizeof(buf), "%s", dir);
+             else snprintf(buf, sizeof(buf), "%s", dir);
           }
-        if (wd->only_folder && !ecore_file_is_dir(buf))
-          eina_stringshare_replace(&wd->selection, ecore_file_dir_get(buf));
-        else
-          eina_stringshare_replace(&wd->selection, buf);
+        else snprintf(buf, sizeof(buf), "%s", dir);
+
+        if (sd->only_folder && !ecore_file_is_dir(buf))
+          eina_stringshare_replace(&sd->selection, ecore_file_dir_get(buf));
+        else eina_stringshare_replace(&sd->selection, buf);
+
         if (dir) free(dir);
-        return wd->selection;
+        return sd->selection;
      }
 
-   if (wd->mode == ELM_FILESELECTOR_LIST)
+   if (sd->mode == ELM_FILESELECTOR_LIST)
      {
-        Elm_Object_Item *gl_it = elm_genlist_selected_item_get(wd->files_list);
+        Elm_Object_Item *gl_it = elm_genlist_selected_item_get(sd->files_list);
+
         if (gl_it) return elm_object_item_data_get(gl_it);
      }
    else
      {
-        Elm_Object_Item *gg_it = elm_gengrid_selected_item_get(wd->files_grid);
+        Elm_Object_Item *gg_it = elm_gengrid_selected_item_get(sd->files_grid);
+
         if (gg_it) return elm_object_item_data_get(gg_it);
      }
 
-   return wd->path;
+   return sd->path;
 }
 
 EAPI Eina_Bool
 elm_fileselector_selected_set(Evas_Object *obj,
-                              const char  *_path)
+                              const char *_path)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return EINA_FALSE;
-
    Eina_Bool ret = EINA_TRUE;
    char *path;
+
+   ELM_FILESELECTOR_CHECK(obj) EINA_FALSE;
+   ELM_FILESELECTOR_DATA_GET(obj, sd);
+
    path = ecore_file_realpath(_path);
 
-   if (ecore_file_is_dir(path))
-     _populate(obj, path, NULL);
+   if (ecore_file_is_dir(path)) _populate(obj, path, NULL);
    else
      {
         if (!ecore_file_exists(path))
@@ -1226,19 +1255,19 @@ elm_fileselector_selected_set(Evas_Object *obj,
           }
 
         _populate(obj, ecore_file_dir_get(path), NULL);
-        if (wd->filename_entry)
+        if (sd->filename_entry)
           {
              char *s;
-             
+
              s = elm_entry_utf8_to_markup(ecore_file_file_get(path));
              if (s)
                {
-                  elm_object_text_set(wd->filename_entry, s);
+                  elm_object_text_set(sd->filename_entry, s);
                   free(s);
                }
-             else
-               elm_object_text_set(wd->filename_entry, "");
-             eina_stringshare_replace(&wd->selection, path);
+             else elm_object_text_set(sd->filename_entry, "");
+
+             eina_stringshare_replace(&sd->selection, path);
           }
      }
 
@@ -1246,4 +1275,3 @@ clean_up:
    free(path);
    return ret;
 }
-
index bf11c67..7e0a4e8 100644 (file)
  * library, the second form of view will display preview thumbnails
  * of files which it supports.
  *
- * Smart callbacks one can register to:
+ * This widget inherits from the @ref Layout one, so that all the
+ * functions acting on it also work for file selector objects.
  *
+ * This widget emits the following signals, besides the ones sent from
+ * @ref Layout:
  * - @c "selected" - the user has clicked on a file (when not in
  *      folders-only mode) or directory (when in folders-only mode)
  * - @c "directory,open" - the list has been populated with new