Hi raster, hi all.

I'm working on the elementary version of edje_editor and I need to write
some new widgets.
I started with the File Selector widget because it is also mentioned in the
elementary TODO ;)

Attached you can find the first patch that add the new widget and a new test
page.
I have also posted the patch at: http://pastebin.com/m1396006
...for fast reading, or in the case I have problems with attachment ;)

I try to make it more 'elementary' as I can: It fit well also on small
screen!
a screenshot is at: http://imagebin.ca/view/t8ZiuW.html


The current API: Evas_Object *elm_fileselector_add(Evas_Object *parent);
const char*  elm_fileselector_selected_get(Evas_Object *obj);
void         elm_fileselector_path_set(Evas_Object *obj, const char *path)
void         elm_fileselector_expandable_set(Evas_Object *obj, Eina_Bool
expand);


I have some questions:
 * Should the file elm_fileselector.c be named elc_ instead of elm_ ?? elc_
means complex? and what means els_?
 * In the fileselector widget I show the subwidgets on elm_fileselector_add
(like in elc_notepad.c). Is this right? or is better to show/hide
   all subs in the obj SHOW/HIDE smartcallback ?? so that we can corretcly
use evas_object_show/hide(fileselector)


And this is the todo for the widget
+/*
+ * TODO
+ *  userdefined icon/label callback
+ *  show/hide/add buttons ???
+ *  need a background ???
+ *  save mode (you can type a name somewhere)
+ *  show/Hide hidden files
+ *  double click to choose a file
+ *  find a way to 'sort directory first'
+ *  multiselection
+ *  write docs
+ */


What do you think? some suggestions?

Hope you like it.
DaveMDS
Index: src/lib/elm_fileselector.c
===================================================================
--- src/lib/elm_fileselector.c	(revisione 0)
+++ src/lib/elm_fileselector.c	(revisione 0)
@@ -0,0 +1,426 @@
+/* 
+ * TODO
+ *  userdefined icon/label cb
+ *  show/hide/add buttons ???
+ *  need a background ???
+ *  save mode (you can type a name somewhere)
+ *  show/Hide hidden files
+ *  double click to choose a file
+ *  find a way to 'sort directory first'
+ *  multiselection
+ *  write docs
+ */
+
+#include <Elementary.h>
+#include <Ecore_Str.h>
+#include "elm_priv.h"
+
+
+typedef struct _Widget_Data Widget_Data;
+
+struct _Widget_Data
+{
+   Evas_Object *vbox, *entry, *list;
+   const char *path;
+   Eina_Bool expand;
+};
+
+Elm_Genlist_Item_Class itc;
+
+static void _populate(Evas_Object *obj, const char *path, Elm_Genlist_Item *parent);
+
+
+/***  ELEMENTARY WIDGET  ***/
+static void
+_del_hook(Evas_Object *obj)
+{
+   Widget_Data *wd = elm_widget_data_get(obj);
+   if (wd->path) eina_stringshare_del(wd->path);
+   free(wd);
+}
+
+static void
+_sizing_eval(Evas_Object *obj)
+{
+   Widget_Data *wd = elm_widget_data_get(obj);
+   Evas_Coord minw = -1, minh = -1;
+
+   evas_object_size_hint_min_get(wd->vbox, &minw, &minh);
+   evas_object_size_hint_min_set(obj, minw, minh);
+
+   printf("***** SIZING EVAL [min %d %d] *************\n", minw, minh);
+}
+
+/***  GENLIST "MODEL"  ***/
+static char*
+_itc_label_get(const void *data, Evas_Object *obj, const char *source)
+{
+   //~ printf("LABEL_GET: %s\n", (char*) data);
+   return strdup(ecore_file_file_get(data)); // NOTE this will be free() by the caller
+}
+
+static Evas_Object*
+_itc_icon_get(const void *data, Evas_Object *obj, const char *source)
+{
+   Evas_Object *ic;
+
+   //~ printf("ICON GET for %s (source: %s)\n", (char*)data, source);
+
+   if (!strcmp(source, "elm.swallow.icon"))
+     {
+	ic = elm_icon_add(obj);
+	if (ecore_file_is_dir((char*)data))
+	  elm_icon_standard_set(ic, "apps");   // TODO we need at least a standard 'folder' and 'file' icon
+	else
+	  elm_icon_standard_set(ic, "chat");
+	evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
+	evas_object_show(ic);
+	return ic;
+     }
+
+   return NULL;
+}
+
+static Eina_Bool 
+_itc_state_get(const void *data, Evas_Object *obj, const char *source)
+{
+   return EINA_FALSE;
+}
+
+static void
+_itc_del(const void *data, Evas_Object *obj)
+{
+   //~ printf("DEL DATA [%s]\n", (char*)data);
+   eina_stringshare_del(data);
+}
+
+static void
+_expand(void *data, Evas_Object *obj, void *event_info)
+{
+   Elm_Genlist_Item *it = event_info;
+   const char *path = elm_genlist_item_data_get(it);
+
+   printf("EXPAND %s\n", path);
+   _populate(data, path, it);
+}
+
+static void
+_contract(void *data, Evas_Object *obj, void *event_info)
+{
+   Elm_Genlist_Item *it = event_info;
+   const char *path = elm_genlist_item_data_get(it);
+
+   printf("CONTRACT %s\n", path);
+   elm_genlist_item_subitems_clear(it);
+}
+
+static void
+_expand_req(void *data, Evas_Object *obj, void *event_info)
+{
+   Elm_Genlist_Item *it = event_info;
+   elm_genlist_item_expanded_set(it, 1);
+}
+
+static void
+_contract_req(void *data, Evas_Object *obj, void *event_info)
+{
+   Elm_Genlist_Item *it = event_info;
+   elm_genlist_item_expanded_set(it, 0);
+}
+
+/***  PRIVATES  ***/
+static void
+_sel(void *data, Evas_Object *obj, void *event_info)
+{
+   const char *path = elm_genlist_item_data_get(event_info);
+   const char *p;
+
+   if (ecore_file_is_dir(path))
+     {
+	printf("SELECTED DIR: %s\n", path);
+	// keep a ref to path 'couse it will be destroyed by _populate
+	p = eina_stringshare_add(path);
+	_populate(data, p, NULL);
+	eina_stringshare_del(p);
+	return;
+     }
+
+   evas_object_smart_callback_call(data, "selected", (void*)path);
+}
+
+static void
+_up(void *data, Evas_Object *obj, void *event_info)
+{
+   Widget_Data *wd = elm_widget_data_get(data);
+   char *parent = ecore_file_dir_get(wd->path);
+
+   _populate(data, parent, NULL);
+   free(parent);
+}
+
+static void
+_home(void *data, Evas_Object *obj, void *event_info)
+{
+   _populate(data, getenv("HOME"), NULL);
+}
+
+static void
+_ok(void *data, Evas_Object *obj, void *event_info)
+{
+   evas_object_smart_callback_call(data, "done",
+				   (void*)elm_fileselector_selected_get(data));
+}
+
+static void
+_canc(void *data, Evas_Object *obj, void *event_info)
+{
+   evas_object_smart_callback_call(data, "done", NULL);
+}
+
+static void
+_anchor_clicked(void *data, Evas_Object *obj, void *event_info)
+{
+   Widget_Data *wd = elm_widget_data_get(data);
+
+   Elm_Entry_Anchor_Info *info = event_info;
+   const char *p;
+
+   printf("ANCHOR CLICKED %s\n", info->name);
+
+  // keep a ref to path 'couse it will be destroyed by _populate
+  p = eina_stringshare_add(info->name);
+  _populate(data, p, NULL);
+  eina_stringshare_del(p);
+
+  //~ evas_object_smart_callback_call(data, "selected", (void*)path);
+}
+
+_do_anchors(Evas_Object *obj, const char *path)
+{
+   Widget_Data *wd = elm_widget_data_get(obj);
+   char **tok, buf[PATH_MAX*3];
+   int i, j;
+
+   //~ printf("ANCHORIZE...\n");
+
+   buf[0] = '\0';
+   tok = ecore_str_split(path, "/", 0);
+   for (i = 0; tok[i]; i++)
+     {
+	if (strlen(tok[i]) < 1) continue;
+	//~ printf("TOK: %s\n", tok[i]);
+	ecore_strlcat(buf, "/<a href=", sizeof(buf));
+	for (j = 0; j <= i; j++)
+	  {
+	     if (strlen(tok[j]) < 1) continue;
+	     //~ printf("REV: %s\n",tok[j]);
+	     ecore_strlcat(buf, "/", sizeof(buf));
+	     ecore_strlcat(buf, tok[j], sizeof(buf));
+	  }
+	ecore_strlcat(buf, ">", sizeof(buf));
+	ecore_strlcat(buf, tok[i], sizeof(buf));
+	ecore_strlcat(buf, "</a>", sizeof(buf));
+     }
+   free(tok[0]);
+   free(tok);
+   
+   //~ printf("ANCHOR: %s\n", buf);
+   elm_entry_entry_set(wd->entry, buf);
+}
+
+static void
+_populate(Evas_Object *obj, const char *path, Elm_Genlist_Item *parent)
+{
+   Widget_Data *wd = elm_widget_data_get(obj);
+   
+   DIR *dir;
+   struct dirent *dp;
+   char buf[PATH_MAX];
+   char *real;
+
+   if (!ecore_file_is_dir(path)) return;
+
+   dir = opendir(path);
+   if (!dir) return;
+
+   if (!parent)
+     {
+	elm_genlist_clear(wd->list);
+	if (wd->path) eina_stringshare_del(wd->path);
+	wd->path = eina_stringshare_add(path);
+	_do_anchors(obj, path);
+     }
+
+   while ((dp = readdir(dir)) != NULL)
+     {
+        if (dp->d_name[0] == '.') continue; // TODO make this configurable
+	snprintf(buf, sizeof(buf), "%s/%s", path, dp->d_name);
+	real = ecore_file_realpath(buf); //TODO this will resolv symlinks...I dont like it
+	//~ printf("FILE: %s\n", real);
+	elm_genlist_item_append(wd->list, &itc,
+				eina_stringshare_add(real), /* item data */
+				parent,
+				(wd->expand && ecore_file_is_dir(real)) ? 
+				  ELM_GENLIST_ITEM_SUBITEMS : ELM_GENLIST_ITEM_NONE,
+				NULL, NULL);
+	free(real);
+     }
+   closedir(dir);
+}
+
+
+/***  API  ***/
+EAPI Evas_Object *
+elm_fileselector_add(Evas_Object *parent)
+{
+   Evas_Object *obj, *ic, *bt, *box;
+   Evas *e;
+   Widget_Data *wd;
+
+   // Elementary Widget
+   wd = ELM_NEW(Widget_Data);
+   wd->path = NULL;
+   wd->expand = EINA_FALSE;
+   e = evas_object_evas_get(parent);
+   obj = elm_widget_add(e);
+   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);
+
+   // TODO Do we need a bg object? a frame?
+
+   // vbox
+   wd->vbox = elm_box_add(parent);
+   evas_object_size_hint_weight_set(wd->vbox, 1.0, 1.0);
+   elm_widget_resize_object_set(obj, wd->vbox);
+   evas_object_show(wd->vbox);
+
+   // buttons box
+   box = elm_box_add(parent);
+   elm_box_horizontal_set(box, 1);
+   elm_widget_sub_object_add(obj, box);
+   elm_box_pack_end(wd->vbox, box);
+   evas_object_size_hint_align_set(box, 0.0, 0.0);
+   evas_object_show(box);
+   
+   // up btn
+   ic = elm_icon_add(parent);
+   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);
+   elm_button_icon_set(bt, ic);
+   elm_button_label_set(bt, "Up");
+   evas_object_size_hint_align_set(bt, 0.0, 0.0);
+   elm_widget_sub_object_add(obj, bt);
+   elm_box_pack_end(box, bt);
+   evas_object_smart_callback_add(bt, "clicked", _up, obj);
+   evas_object_show(bt);
+   
+   // home btn
+   ic = elm_icon_add(parent);
+   elm_icon_standard_set(ic, "home");
+   evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
+   bt = elm_button_add(parent);
+   elm_button_icon_set(bt, ic);
+   elm_button_label_set(bt, "Home");
+   evas_object_size_hint_align_set(bt, 0.0, 0.0);
+   elm_widget_sub_object_add(obj, bt);
+   elm_box_pack_end(box, bt);
+   evas_object_smart_callback_add(bt, "clicked", _home, obj);
+   evas_object_show(bt);
+
+   // entry
+   wd->entry = elm_entry_add(parent);
+   elm_widget_sub_object_add(obj, wd->entry);
+   elm_entry_entry_set(wd->entry, "TODO");
+   elm_entry_editable_set(wd->entry, 0);
+   elm_entry_single_line_set(wd->entry, EINA_TRUE);
+   evas_object_size_hint_weight_set(wd->entry, 1.0, 0.0);
+   evas_object_size_hint_align_set(wd->entry, 0.0, 0.0);
+   elm_box_pack_end(wd->vbox, wd->entry);
+   evas_object_show(wd->entry);
+   
+   evas_object_smart_callback_add(wd->entry, "anchor,clicked", _anchor_clicked, obj);
+   //TODO try this
+   //~ evas_object_event_callback_add(wd->entry, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
+				  //~ _changed_size_hints, obj);
+
+   // genlist
+   itc.item_style     = "default";
+   itc.func.label_get = _itc_label_get;
+   itc.func.icon_get  = _itc_icon_get;
+   itc.func.state_get = _itc_state_get;
+   itc.func.del       = _itc_del;
+
+   wd->list = elm_genlist_add(parent);
+   evas_object_size_hint_align_set(wd->list, -1.0, -1.0);
+   evas_object_size_hint_weight_set(wd->list, 1.0, 1.0);
+   evas_object_size_hint_min_set(wd->list, 100, 100);
+   elm_widget_sub_object_add(obj, wd->list);
+   elm_box_pack_end(wd->vbox, wd->list);
+   evas_object_show(wd->list);
+
+   evas_object_smart_callback_add(wd->list, "selected", _sel, obj);
+   evas_object_smart_callback_add(wd->list, "expand,request", _expand_req, obj);
+   evas_object_smart_callback_add(wd->list, "contract,request", _contract_req, obj);
+   evas_object_smart_callback_add(wd->list, "expanded", _expand, obj);
+   evas_object_smart_callback_add(wd->list, "contracted", _contract, obj);
+
+   // buttons box
+   box = elm_box_add(parent);
+   elm_box_horizontal_set(box, 1);
+   elm_widget_sub_object_add(obj, box);
+   elm_box_pack_end(wd->vbox, box);
+   evas_object_show(box);
+   
+   // cancel btn
+   bt = elm_button_add(parent);
+   elm_button_label_set(bt, "Cancel");
+   elm_widget_sub_object_add(obj, bt);
+   elm_box_pack_end(box, bt);
+   evas_object_smart_callback_add(bt, "clicked", _canc, obj);
+   evas_object_show(bt);
+
+   // ok btn
+   bt = elm_button_add(parent);
+   elm_button_label_set(bt, "Ok");
+   elm_widget_sub_object_add(obj, bt);
+   elm_box_pack_end(box, bt);
+   evas_object_smart_callback_add(bt, "clicked", _ok, obj);
+   evas_object_show(bt);
+
+   // Is this the right way to show sub-objs ?? or use the show/hode cbs ??
+   //~ evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _show, obj);
+   //~ evas_object_event_callback_add(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
+				       //~ _changed_size_hints, obj);
+				       
+
+   _sizing_eval(obj);
+   return obj;
+}
+
+EAPI void
+elm_fileselector_expandable_set(Evas_Object *obj, Eina_Bool expand)
+{
+   Widget_Data *wd = elm_widget_data_get(obj);
+   wd->expand = expand;
+}
+
+EAPI const char*
+elm_fileselector_selected_get(Evas_Object *obj)
+{
+   Widget_Data *wd = elm_widget_data_get(obj);
+   Elm_Genlist_Item *it;
+   
+   it = elm_genlist_selected_item_get(wd->list);
+   if (!it) return NULL;
+   
+   return elm_genlist_item_data_get(it);
+}
+
+EAPI void
+elm_fileselector_path_set(Evas_Object *obj, const char *path)
+{
+   _populate(obj, path, NULL);
+}
Index: src/lib/Elementary.h.in
===================================================================
--- src/lib/Elementary.h.in	(revisione 41316)
+++ src/lib/Elementary.h.in	(copia locale)
@@ -699,6 +699,15 @@
    EAPI Evas_Object *elm_pager_content_top_get(Evas_Object *obj);
    /* smart callbacks called:
     */
+    
+   EAPI Evas_Object *elm_fileselector_add(Evas_Object *parent);
+   EAPI const char*  elm_fileselector_selected_get(Evas_Object *obj);
+   EAPI void         elm_fileselector_path_set(Evas_Object *obj, const char *path);
+   EAPI void         elm_fileselector_expandable_set(Evas_Object *obj, Eina_Bool expand);
+   /* smart callbacks called:
+    * "selected" - the user click on a file
+    * "done" - the user click on the ok or cancel buttons
+    */
 
 #ifdef __cplusplus
 }
Index: src/lib/Makefile.am
===================================================================
--- src/lib/Makefile.am	(revisione 41316)
+++ src/lib/Makefile.am	(copia locale)
@@ -54,6 +54,7 @@
 elm_check.c \
 elm_radio.c \
 elm_pager.c \
+elm_fileselector.c \
 \
 elc_notepad.c \
 elc_anchorview.c \
Index: src/bin/test.c
===================================================================
--- src/bin/test.c	(revisione 41316)
+++ src/bin/test.c	(copia locale)
@@ -3478,6 +3478,61 @@
 }
 
 static void
+my_bt_39_done(void *data, Evas_Object *obj, void *event_info)
+{
+   /* event_info conatin the full path of the selected file
+    * or NULL if none is selected or cancel is pressed */
+   const char *selected = event_info;
+   
+   if (selected)
+      printf("Selected file: %s\n", selected);
+   else
+      evas_object_del(data); /* delete the test window */
+}
+
+static void
+my_bt_39_selected(void *data, Evas_Object *obj, void *event_info)
+{
+   /* event_info conatin the full path of the selected file */
+   const char *selected = event_info;
+   printf("Selected file: %s\n", selected);
+   
+   /* or you can query the selection */
+   printf("or: %s\n", elm_fileselector_selected_get(obj));
+}
+
+static void
+my_bt_39(void *data, Evas_Object *obj, void *event_info)
+{
+   Evas_Object *win, *fs, *bg;
+   char buf[PATH_MAX];
+
+   win = elm_win_add(NULL, "fileselector", ELM_WIN_BASIC);
+   elm_win_title_set(win, "File Selector");
+   elm_win_autodel_set(win, 1);
+
+   bg = elm_bg_add(win);
+   elm_win_resize_object_add(win, bg);
+   evas_object_size_hint_weight_set(bg, 1.0, 1.0);
+   evas_object_show(bg);
+
+   fs = elm_fileselector_add(win);
+   elm_fileselector_expandable_set(fs, EINA_FALSE);
+   /* start the fileselector in the home dir */
+   elm_fileselector_path_set(fs, getenv("HOME"));
+   /* allow fs to expand in x & y */
+   evas_object_size_hint_weight_set(fs, 1.0, 1.0);
+   elm_win_resize_object_add(win, fs);
+   evas_object_show(fs);
+   /* the 'done' cb is called when the user press ok/cancel */
+   evas_object_smart_callback_add(fs, "done", my_bt_39_done, win);
+   evas_object_smart_callback_add(fs, "selected", my_bt_39_selected, win);
+
+   evas_object_resize(win, 240, 350);
+   evas_object_show(win);
+}
+
+static void
 my_win_main(void)
 {
    Evas_Object *win, *bg, *bx0, *lb, *li, *fr;
@@ -3553,6 +3608,7 @@
    elm_box_pack_end(bx0, li);
    evas_object_show(li);
 
+   elm_list_item_append(li, "File Selector", NULL, NULL, my_bt_39, NULL);
    elm_list_item_append(li, "Bg Plain", NULL, NULL, my_bt_1, NULL);
    elm_list_item_append(li, "Bg Image", NULL, NULL, my_bt_2, NULL);
    elm_list_item_append(li, "Icon Transparent", NULL, NULL, my_bt_3, NULL);
@@ -3591,6 +3647,7 @@
    elm_list_item_append(li, "Genlist Tree", NULL, NULL, my_bt_36, NULL);
    elm_list_item_append(li, "Genlist 5", NULL, NULL, my_bt_37, NULL);
    elm_list_item_append(li, "Window States", NULL, NULL, my_bt_38, NULL);
+   
 
    elm_list_go(li);
 
------------------------------------------------------------------------------
Enter the BlackBerry Developer Challenge  
This is your chance to win up to $100,000 in prizes! For a limited time, 
vendors submitting new applications to BlackBerry App World(TM) will have
the opportunity to enter the BlackBerry Developer Challenge. See full prize  
details at: http://p.sf.net/sfu/Challenge
_______________________________________________
enlightenment-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to