hermet pushed a commit to branch master.

http://git.enlightenment.org/tools/enventor.git/commit/?id=4ee083fdac5d91cbaab8283c54e38f187104d70a

commit 4ee083fdac5d91cbaab8283c54e38f187104d70a
Author: Hermet Park <her...@hermet.pe.kr>
Date:   Fri Apr 22 15:39:24 2016 +0900

    edc_navigator: feature extension.
    
    Now this function has an option for auto contraction.
    
    User could choose one of them for their taste.
---
 src/bin/base_gui.c          |   39 +-
 src/bin/edc_navigator.c     | 1030 ++++++++++++++++++++++++++++++-------------
 src/bin/main.c              |    6 +-
 src/include/base_gui.h      |    3 +-
 src/include/edc_navigator.h |    1 -
 5 files changed, 739 insertions(+), 340 deletions(-)

diff --git a/src/bin/base_gui.c b/src/bin/base_gui.c
index 1282f8e..6ba4100 100644
--- a/src/bin/base_gui.c
+++ b/src/bin/base_gui.c
@@ -7,7 +7,6 @@ typedef struct base_s
    Evas_Object *console;
    Evas_Object *enventor;
    Ecore_Timer *edc_navi_update_timer;
-   Ecore_Timer *edc_navi_reload_timer;
    Eina_Bool console_msg : 1;
 } base_data;
 
@@ -34,25 +33,10 @@ win_resize_cb(void *data EINA_UNUSED, Evas *o EINA_UNUSED, 
Evas_Object *obj,
 }
 
 static Eina_Bool
-edc_navigator_reload_timer_cb(void *data)
-{
-   base_data *bd = data;
-
-   edc_navigator_reload(stats_group_name_get());
-
-   bd->edc_navi_reload_timer = NULL;
-
-   return ECORE_CALLBACK_CANCEL;
-}
-
-static Eina_Bool
 edc_navigator_update_timer_cb(void *data)
 {
-   base_data *bd = g_bd;
-
-   const char *group_name = data;
-   edc_navigator_group_update(group_name);
-
+   base_data *bd = data;
+   edc_navigator_group_update(stats_group_name_get());
    bd->edc_navi_update_timer = NULL;
 
    return ECORE_CALLBACK_CANCEL;
@@ -119,7 +103,7 @@ void base_edc_navigator_toggle(Eina_Bool toggle)
 
    if (config_edc_navigator_get())
      {
-        base_edc_navigator_reload();
+        base_edc_navigator_group_update();
         elm_object_signal_emit(bd->layout, "elm,state,edc_navigator,show", "");
      }
    else
@@ -241,7 +225,6 @@ base_gui_term(void)
    if (!bd) return;
 
    ecore_timer_del(bd->edc_navi_update_timer);
-   ecore_timer_del(bd->edc_navi_reload_timer);
    file_browser_term();
    edc_navigator_term();
    panes_term();
@@ -251,7 +234,7 @@ base_gui_term(void)
 }
 
 void
-base_edc_navigator_group_update(const char *group_name)
+base_edc_navigator_group_update(void)
 {
    if (!config_edc_navigator_get()) return;
 
@@ -261,20 +244,6 @@ base_edc_navigator_group_update(const char *group_name)
    ecore_timer_del(bd->edc_navi_update_timer);
    bd->edc_navi_update_timer = ecore_timer_add(EDC_NAVIGATOR_UPDATE_TIME,
                                                edc_navigator_update_timer_cb,
-                                               group_name);
-}
-
-void
-base_edc_navigator_reload(void)
-{
-   if (!config_edc_navigator_get()) return;
-
-   base_data *bd = g_bd;
-   if (!bd) return;
-
-   ecore_timer_del(bd->edc_navi_reload_timer);
-   bd->edc_navi_reload_timer = ecore_timer_add(EDC_NAVIGATOR_UPDATE_TIME,
-                                               edc_navigator_reload_timer_cb,
                                                bd);
 }
 
diff --git a/src/bin/edc_navigator.c b/src/bin/edc_navigator.c
index 3ba946f..b2c25bb 100644
--- a/src/bin/edc_navigator.c
+++ b/src/bin/edc_navigator.c
@@ -3,20 +3,23 @@
 #define EDJE_EDIT_IS_UNSTABLE_AND_I_KNOW_ABOUT_IT
 #include <Edje_Edit.h>
 
+#define IDX_MAX 999999
+#define PROGRAM_IDX (IDX_MAX - 1)
+
+typedef struct group_it_s group_it;
+typedef struct part_it_s part_it;
+typedef struct state_it_s state_it;
+typedef struct programs_it_s programs_it;
+typedef struct program_it_s program_it;
+typedef struct list_it_s list_it;
+
 typedef struct edc_navigator_s
 {
+   Evas_Object *box;
    Evas_Object *genlist;
-   Elm_Object_Item *programs_it;
-
-   Eina_List *group_items;                 //group object item
-   Eina_List *part_items;                  //part object item
-   Eina_List *state_items;                 //state object item
-   Eina_List *program_items;               //program object item
+   Evas_Object *check;
 
-   Eina_List *group_list;                  //group name list
-   Eina_List *part_list;                   //part name list
-   Eina_List *state_list;                  //state name list
-   Eina_List *program_list;                //program name list
+   Eina_List *groups;
 
    Elm_Genlist_Item_Class *group_itc;
    Elm_Genlist_Item_Class *part_itc;
@@ -24,15 +27,75 @@ typedef struct edc_navigator_s
    Elm_Genlist_Item_Class *programs_itc;
    Elm_Genlist_Item_Class *program_itc;
 
-   Eina_Bool group_select_skip : 1;
+   Eina_Bool auto_contract : 1;
 
 } navi_data;
 
-typedef struct part_item_data_s
+typedef enum
+{
+   Item_Type_Group = 0,
+   Item_Type_Part = 1,
+   Item_Type_State = 2,
+   Item_Type_Programs = 3,
+   Item_Type_Program = 4
+} Item_Type;
+
+struct list_it_s
+{
+   Item_Type type;
+   int idx;
+};
+
+struct programs_it_s
 {
-   const char *text;
+   list_it tag;
+   Elm_Object_Item *it;
+   Eina_List *programs;
+   group_it *git;
+};
+
+struct group_it_s
+{
+   list_it tag;
+   char *name;
+   Elm_Object_Item *it;
+   Eina_List *parts;
+   navi_data *nd;
+
+   programs_it programs;
+
+   Eina_Bool discarded: 1;
+};
+
+struct part_it_s
+{
+   list_it tag;
+   char *name;
+   Elm_Object_Item *it;
    Edje_Part_Type type;
-} part_item_data;
+   Eina_List *states;
+   group_it *git;
+
+   Eina_Bool discarded : 1;
+};
+
+struct state_it_s
+{
+   list_it tag;
+   char *name;
+   Elm_Object_Item *it;
+   part_it *pit;
+};
+
+struct program_it_s
+{
+   list_it tag;
+   char *name;
+   Elm_Object_Item *it;
+   programs_it *pit;
+
+   Eina_Bool discarded : 1;
+};
 
 static navi_data *g_nd = NULL;
 
@@ -44,23 +107,140 @@ static const char *TEXTBLOCK_TYPE_STR = "textblock";
 static const char *SPACER_TYPE_STR = "spacer";
 static const char *PART_TYPE_STR = "part";
 
-static void
-gl_part_selected_cb(void *data, Evas_Object *obj EINA_UNUSED, void 
*event_info);
-static void
-sub_programs_remove(navi_data *nd);
-static void
-states_remove(navi_data *nd);
+static void group_contract(group_it *git);
+static void part_contract(part_it *pit);
+static void programs_contract(programs_it *pit);
 
 /*****************************************************************************/
 /* Internal method implementation                                            */
 /*****************************************************************************/
 
-const char *
-part_type_get(Elm_Object_Item *it)
+static int
+gl_comp_func(const void *pa, const void *pb)
+{
+   const Elm_Object_Item *a = pa;
+   const Elm_Object_Item *b = pb;
+
+   list_it *it_a = (list_it *) elm_object_item_data_get(a);
+   list_it *it_b = (list_it *) elm_object_item_data_get(b);
+
+   return (it_a->idx - it_b->idx);
+}
+
+static void
+check_changed_cb(void *data, Evas_Object *obj, void *event_info)
+{
+   navi_data *nd = data;
+   nd->auto_contract = elm_check_state_get(obj);
+
+   if (!nd->auto_contract) return;
+
+   // Contract all groups instantly.
+   Eina_List *l;
+   group_it *git;
+
+   EINA_LIST_FOREACH(nd->groups, l, git)
+     group_contract(git);
+}
+
+static void
+navigator_state_free(state_it *sit)
+{
+   elm_object_item_del(sit->it);
+   free(sit->name);
+   free(sit);
+}
+
+static void
+navigator_states_clear(part_it *pit)
+{
+   state_it *sit;
+   EINA_LIST_FREE(pit->states, sit)
+     navigator_state_free(sit);
+
+   pit->states = NULL;
+}
+
+static void
+navigator_program_free(program_it *pit)
+{
+   elm_object_item_del(pit->it);
+   free(pit->name);
+   free(pit);
+}
+
+static void
+navigator_sub_programs_clear(programs_it *pit)
+{
+   program_it *spit;
+   EINA_LIST_FREE(pit->programs, spit)
+     navigator_program_free(spit);
+
+   pit->programs = NULL;
+}
+
+static void
+navigator_part_free(part_it *pit)
+{
+   state_it *sit;
+   EINA_LIST_FREE(pit->states, sit)
+     navigator_state_free(sit);
+
+   elm_object_item_del(pit->it);
+   free(pit->name);
+   free(pit);
+}
+
+static void
+navigator_parts_clear(group_it *git)
+{
+   part_it *pit;
+   EINA_LIST_FREE(git->parts, pit)
+     navigator_part_free(pit);
+
+   git->parts = NULL;
+}
+
+static void
+navigator_programs_clear(group_it *git)
+{
+   programs_it *pit = &git->programs;
+
+   if (!pit->it) return;
+
+   program_it *spit;
+   EINA_LIST_FREE(pit->programs, spit)
+     navigator_program_free(spit);
+
+   pit->programs = NULL;
+   elm_object_item_del(pit->it);
+   pit->it = NULL;
+}
+
+static void
+navigator_group_free(group_it *git)
+{
+   navigator_parts_clear(git);
+   navigator_programs_clear(git);
+   elm_object_item_del(git->it);
+   free(git->name);
+   free(git);
+}
+
+static void
+navigator_groups_clear(navi_data *nd)
 {
-   part_item_data *item_data = elm_object_item_data_get(it);
+   group_it *git;
+   EINA_LIST_FREE(nd->groups, git)
+     navigator_group_free(git);
+
+   nd->groups = NULL;
+}
 
-   switch (item_data->type)
+static const char *
+part_type_get(part_it *pit)
+{
+   switch (pit->type)
      {
       case EDJE_PART_TYPE_RECTANGLE:
          return RECT_TYPE_STR;
@@ -430,87 +610,72 @@ end:
    free(utf8);
 }
 
-static char *
-gl_text_get_cb(void *data, Evas_Object *obj EINA_UNUSED,
-               const char *part EINA_UNUSED)
-{
-   const char *text = data;
-   return strdup(text);
-}
-
 /* State Related */
 
-static void
-gl_state_selected_cb(void *data, Evas_Object *obj EINA_UNUSED, void 
*event_info)
+static char *
+gl_state_text_get_cb(void *data, Evas_Object *obj EINA_UNUSED,
+                     const char *part EINA_UNUSED)
 {
-   navi_data *nd = data;
-
-   Elm_Object_Item *it = event_info;
-
-   sub_programs_remove(nd);
-
-   Elm_Object_Item *parent_it = elm_genlist_item_parent_get(it);
-
-   const char *part_type = part_type_get(parent_it);
-
-   find_state_proc(stats_group_name_get(),
-                   elm_object_item_text_get(parent_it), part_type,
-                   elm_object_item_text_get(it));
+   state_it *sit = data;
+   return strdup(sit->name);
 }
 
 static void
-states_remove(navi_data *nd)
+gl_state_selected_cb(void *data, Evas_Object *obj EINA_UNUSED,
+                     void *event_info EINA_UNUSED)
 {
-   Elm_Object_Item *it;
-   EINA_LIST_FREE(nd->state_items, it) elm_object_item_del(it);
-   if (nd->state_list)
-     {
-        edje_edit_string_list_free(nd->state_list);
-        nd->state_list = NULL;
-     }
+   state_it *sit = data;
+   find_state_proc(sit->pit->git->name, sit->pit->name, 
part_type_get(sit->pit),
+                   sit->name);
+
 }
 
 static void
-states_reload(navi_data *nd, Elm_Object_Item *part_it)
+states_update(navi_data *nd, part_it *pit)
 {
-   const char *part = elm_object_item_text_get(part_it);
-   if (!part) return;
-
-   Eina_List *l;
-   Elm_Object_Item *it;
-
-   //Remove Previous Parts
+   navigator_states_clear(pit);
 
-   //FIXME: Maybe we could optimize if parts list hasn't been changed.
-   states_remove(nd);
-
-   //Append States
    Evas_Object *enventor = base_enventor_get();
-   nd->state_list = enventor_object_part_states_list_get(enventor, part);
+   Eina_List *state_list = enventor_object_part_states_list_get(enventor,
+                                                                pit->name);
+   if (!state_list) return;
+
+   //Append state list
    char *name;
+   Eina_List *l;
+   state_it *sit;
+   int idx = 0;
 
-   EINA_LIST_FOREACH(nd->state_list, l, name)
+   EINA_LIST_FOREACH(state_list, l, name)
      {
-        it = elm_genlist_item_append(nd->genlist,
-                                     nd->state_itc,         /* item class */
-                                     name,                  /* item data */
-                                     part_it,               /* parent */
-                                     ELM_GENLIST_ITEM_NONE, /* item type */
-                                     gl_state_selected_cb,  /* select cb */
-                                     nd);                   /* select cb data 
*/
-        nd->state_items = eina_list_append(nd->state_items, it);
+        idx++;
+
+        sit = calloc(1, sizeof(state_it));
+        if (!sit)
+          {
+             EINA_LOG_ERR(_("Failed to allocate Memory!"));
+             continue;
+          }
+        sit->tag.type = Item_Type_State;
+        sit->tag.idx = idx;
+        //Parsing "default" "0.00". We don't take care 0.00 in the state name.
+        const char *brk = strpbrk(name, " ");
+        if (brk) sit->name = strndup(name, brk - name);
+        else sit->name = strdup(name);
+
+        sit->pit = pit;
+        sit->it = elm_genlist_item_sorted_insert(nd->genlist,
+                                                 nd->state_itc,
+                                                 sit,
+                                                 pit->it,
+                                                 ELM_GENLIST_ITEM_NONE,
+                                                 gl_comp_func,
+                                                 gl_state_selected_cb,
+                                                 sit);
+        pit->states = eina_list_append(pit->states, sit);
      }
-}
 
-static char *
-gl_state_text_get_cb(void *data, Evas_Object *obj EINA_UNUSED,
-                     const char *part EINA_UNUSED)
-{
-   const char *text = data;
-   //Parsing "default" "0.00". We don't take care 0.00 in the state name.
-   const char *brk = strpbrk(text, " ");
-   if (brk) return strndup(text, brk - text);
-   else return strdup(text);
+   edje_edit_string_list_free(state_list);
 }
 
 static Evas_Object *
@@ -527,6 +692,14 @@ gl_state_content_get_cb(void *data EINA_UNUSED, 
Evas_Object *obj,
 
 /* Program Related */
 
+static char *
+gl_program_text_get_cb(void *data, Evas_Object *obj EINA_UNUSED,
+                       const char *part EINA_UNUSED)
+{
+   program_it *spit = data;
+   return strdup(spit->name);
+}
+
 static Evas_Object *
 gl_program_content_get_cb(void *data EINA_UNUSED, Evas_Object *obj,
                           const char *part)
@@ -541,102 +714,201 @@ gl_program_content_get_cb(void *data EINA_UNUSED, 
Evas_Object *obj,
 
 
 static void
-gl_program_selected_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED,
-                       void *event_info)
+gl_program_selected_cb(void *data, Evas_Object *obj EINA_UNUSED,
+                       void *event_info EINA_UNUSED)
 {
-   Elm_Object_Item *it = event_info;
-   find_program_proc(stats_group_name_get(), elm_object_item_text_get(it));
+   program_it *spit = data;
+   find_program_proc(spit->pit->git->name, spit->name);
 }
 
 static void
-sub_programs_reload(navi_data *nd, Elm_Object_Item *programs_it)
+sub_programs_update(navi_data *nd, programs_it *pit)
 {
-   const Eina_List *programs = elm_genlist_item_subitems_get(programs_it);
+   navigator_sub_programs_clear(pit);
 
-   //We already reloaded items
-   if (programs) return;
+   Evas_Object *enventor = base_enventor_get();
+   Eina_List *program_list = enventor_object_programs_list_get(enventor);
+   if (!program_list) return;
 
+   //Append program list
    char *name;
    Eina_List *l;
    Elm_Object_Item *it;
+   program_it *spit;
+   int idx = 0;
 
-   EINA_LIST_FOREACH(nd->program_list, l, name)
+   EINA_LIST_FOREACH(program_list, l, name)
      {
-        it = elm_genlist_item_append(nd->genlist,
-                                     nd->program_itc,       /* item class */
-                                     name,                  /* item data */
-                                     programs_it,           /* parent */
-                                     ELM_GENLIST_ITEM_NONE, /* item type */
-                                     gl_program_selected_cb,/* select cb */
-                                     nd);                   /* select cb data 
*/
-        nd->program_items = eina_list_append(nd->program_items, it);
+        idx++;
+
+        spit = calloc(1, sizeof(program_it));
+        if (!spit)
+          {
+             EINA_LOG_ERR(_("Failed to allocate Memory!"));
+             continue;
+          }
+
+        spit->tag.type = Item_Type_Program;
+        spit->tag.idx = idx;
+        spit->name = strdup(name);
+        spit->pit = pit;
+        spit->it = elm_genlist_item_sorted_insert(nd->genlist,
+                                                  nd->program_itc,
+                                                  spit,
+                                                  pit->it,
+                                                  ELM_GENLIST_ITEM_NONE,
+                                                  gl_comp_func,
+                                                  gl_program_selected_cb,
+                                                  spit);
+        pit->programs = eina_list_append(pit->programs, spit);
      }
+
+   edje_edit_string_list_free(program_list);
 }
 
+/* Programs Related */
+
 static void
-sub_programs_remove(navi_data *nd)
+programs_expand(programs_it *pit)
 {
-   if (!nd->programs_it) return;
+   if (elm_genlist_item_expanded_get(pit->it)) return;
 
-   Elm_Object_Item *it;
-   EINA_LIST_FREE(nd->program_items, it) elm_object_item_del(it);
+   elm_genlist_item_expanded_set(pit->it, EINA_TRUE);
+
+   sub_programs_update(pit->git->nd, pit);
+
+   //If auto contraction is enabled, then close other parts
+   if (!(pit->git->nd->auto_contract)) return;
+
+   //Contract part states
+   part_it *pit2;
+   Eina_List *l;
+   EINA_LIST_FOREACH(pit->git->parts, l, pit2)
+     part_contract(pit2);
 }
 
 static void
-gl_programs_del_cb(void *data, Evas_Object *obj EINA_UNUSED)
+programs_contract(programs_it *pit)
 {
-   navi_data *nd = g_nd;
-   if (!nd) return;
+   if (!elm_genlist_item_expanded_get(pit->it)) return;
 
-   Elm_Object_Item *it = data;
-   if (nd->programs_it == it) nd->programs_it = NULL;
-}
+   elm_genlist_item_expanded_set(pit->it, EINA_FALSE);
 
-/* Programs Related */
+   navigator_sub_programs_clear(pit);
+}
 
 static void
 gl_programs_selected_cb(void *data, Evas_Object *obj EINA_UNUSED,
                         void *event_info)
 {
-   navi_data *nd = data;
-   Elm_Object_Item *it = event_info;
-
-   states_remove(nd);
-   sub_programs_reload(nd, it);
+   programs_it *pit = data;
 
-   Elm_Object_Item *parent_it = elm_genlist_item_parent_get(it);
-
-   find_programs_proc(elm_object_item_text_get(parent_it));
+   find_programs_proc(pit->git->name);
 }
 
 static void
-programs_reload(navi_data *nd, Elm_Object_Item *group_it)
+programs_update(navi_data *nd, group_it *git)
 {
-   //FIXME: Maybe we could optimize if programs list hasn't been changed.
-   sub_programs_remove(nd);
+   Evas_Object *enventor = base_enventor_get();
+   Eina_List *program_list = enventor_object_programs_list_get(enventor);
 
-   if (nd->program_list) edje_edit_string_list_free(nd->program_list);
+   //oh, no programs.. 
+   if (!program_list)
+     {
+        navigator_programs_clear(git);
+        return;
+     }
 
-   //Append Parts
-   Evas_Object *enventor = base_enventor_get();
-   nd->program_list = enventor_object_programs_list_get(enventor);
+   programs_it *pit = &git->programs;
+
+   //Create a programs item first time.
+   if (!pit->it)
+     {
+        pit->tag.type = Item_Type_Programs;
+        pit->tag.idx = PROGRAM_IDX;
+        pit->git = git;
+        pit->it = elm_genlist_item_sorted_insert(nd->genlist,
+                                                 nd->programs_itc,
+                                                 pit,
+                                                 git->it,
+                                                 ELM_GENLIST_ITEM_TREE,
+                                                 gl_comp_func,
+                                                 gl_programs_selected_cb,
+                                                 pit);
+        return;
+     }
+
+   if (!elm_genlist_item_expanded_get(pit->it)) return;
+
+   //programs item is already created, it may need to update progam lists.
 
-   //FIXME: Maybe we could optimize if programs list hasn't been changed.
-   elm_object_item_del(nd->programs_it);
-   nd->programs_it = NULL;
+   //1. Prepare for validation.
+   Eina_List *l, *ll;
+   program_it *spit;
+   char *name;
+   int idx = 0;
 
-   if (!nd->program_list) return;
+   EINA_LIST_FOREACH(pit->programs, l, spit)
+     {
+        spit->discarded = EINA_TRUE;
+        spit->tag.idx = IDX_MAX;
+     }
+
+   //2. New programs
+   EINA_LIST_FOREACH(program_list, l, name)
+     {
+        Eina_Bool new_program = EINA_TRUE;
+        idx++;
 
-   //Programs Item
-   nd->programs_it =
-      elm_genlist_item_append(nd->genlist,
-                              nd->programs_itc,        /* item class */
-                              NULL,                    /* item data */
-                              group_it,                /* parent */
-                              ELM_GENLIST_ITEM_NONE,   /* item type */
-                              gl_programs_selected_cb, /* select cb */
-                              nd);                     /* select cb data */
-   elm_object_item_data_set(nd->programs_it, nd->programs_it);
+        //Check if it is existed?
+        EINA_LIST_FOREACH(pit->programs, ll, spit)
+          {
+             if (!strcmp(name, spit->name) &&
+                 (strlen(name) == strlen(spit->name)))
+               {
+                  spit->discarded = EINA_FALSE;
+                  new_program = EINA_FALSE;
+                  //update index of the item
+                  spit->tag.idx = idx;
+                  break;
+               }
+          }
+        if (!new_program) continue;
+
+        //Ok, this program is newly added.
+        spit = calloc(1, sizeof(program_it));
+        if (!spit)
+          {
+             EINA_LOG_ERR(_("Failed to allocate Memory!"));
+             continue;
+          }
+
+        spit->tag.type = Item_Type_Program;
+        spit->tag.idx = idx;
+        spit->name = strdup(name);
+        spit->pit = pit;
+        spit->it = elm_genlist_item_sorted_insert(nd->genlist,
+                                                  nd->program_itc,
+                                                  spit,
+                                                  pit->it,
+                                                  ELM_GENLIST_ITEM_NONE,
+                                                  gl_comp_func,
+                                                  gl_program_selected_cb,
+                                                  spit);
+        pit->programs = eina_list_append(pit->programs, spit);
+     }
+
+   //3. Discarded programs
+   EINA_LIST_FOREACH_SAFE(pit->programs, l, ll, spit)
+     {
+        if (!spit->discarded) continue;
+
+        //Remove them from the previous list.
+        pit->programs = eina_list_remove_list(pit->programs, l);
+        navigator_program_free(spit);
+     }
+
+   edje_edit_string_list_free(program_list);
 }
 
 static char *
@@ -646,7 +918,6 @@ gl_programs_text_get_cb(void *data EINA_UNUSED, Evas_Object 
*obj EINA_UNUSED,
    return strdup("PROGRAMS");
 }
 
-
 static Evas_Object *
 gl_programs_content_get_cb(void *data EINA_UNUSED, Evas_Object *obj,
                            const char *part)
@@ -662,31 +933,24 @@ gl_programs_content_get_cb(void *data EINA_UNUSED, 
Evas_Object *obj,
 
 /* Part Related */
 
-static void
-gl_part_del_cb(void *data, Evas_Object *obj EINA_UNUSED)
-{
-   part_item_data *item_data = data;
-   free(item_data);
-}
-
 static char *
 gl_part_text_get_cb(void *data, Evas_Object *obj EINA_UNUSED,
                     const char *part EINA_UNUSED)
 {
-   part_item_data *item_data = data;
-   return strdup(item_data->text);
+   part_it *pit = data;
+   return strdup(pit->name);
 }
 
 static Evas_Object *
 gl_part_content_get_cb(void *data, Evas_Object *obj, const char *part)
 {
    if (strcmp("elm.swallow.icon", part)) return NULL;
-   part_item_data *item_data = data;
+   part_it *pit = data;
 
    Evas_Object *image = elm_image_add(obj);
    const char *group;
 
-   switch (item_data->type)
+   switch (pit->type)
      {
       case EDJE_PART_TYPE_RECTANGLE:
          group = "navi_rect";
@@ -717,88 +981,248 @@ gl_part_content_get_cb(void *data, Evas_Object *obj, 
const char *part)
 }
 
 static void
-gl_part_selected_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info)
+gl_part_selected_cb(void *data, Evas_Object *obj EINA_UNUSED,
+                    void *event_info EINA_UNUSED)
 {
-   navi_data *nd = data;
-   Elm_Object_Item *it = event_info;
+   part_it *pit = data;
 
-   sub_programs_remove(nd);
+   //Find text cursor position
+   const char *part_type = part_type_get(pit);
+   find_part_proc(pit->git->name, pit->name, part_type);
+}
 
-   states_reload(nd, it);
+static void
+parts_update(navi_data *nd, group_it *git)
+{
+   Evas_Object *enventor = base_enventor_get();
+   Eina_List *part_list = enventor_object_parts_list_get(enventor);
+   Eina_List *l, *ll;
+   part_it *pit;
+   char *name;
+   int idx = 0;
 
-   part_item_data *item_data = elm_object_item_data_get(it);
-   Elm_Object_Item *parent_it = elm_genlist_item_parent_get(it);
+   //1. Prepare for validation.
+   EINA_LIST_FOREACH(git->parts, l, pit)
+     {
+        pit->discarded = EINA_TRUE;
+        pit->tag.idx = IDX_MAX;
+     }
+
+   //2. New parts
+   EINA_LIST_FOREACH(part_list, l, name)
+     {
+        Eina_Bool new_part = EINA_TRUE;
+        idx++;
 
-   const char *part_type = part_type_get(it);
+        //Check if it is existed?
+        EINA_LIST_FOREACH(git->parts, ll, pit)
+          {
+             if (!strcmp(name, pit->name) &&
+                 (strlen(name) == strlen(pit->name)))
+               {
+                  pit->discarded = EINA_FALSE;
+                  new_part = EINA_FALSE;
+                  //update index of the item
+                  pit->tag.idx = idx;
+                  break;
+               }
+
+          }
+        if (!new_part) continue;
+
+        //Ok, this part is newly added.
+        pit = calloc(1, sizeof(part_it));
+        if (!pit)
+          {
+             EINA_LOG_ERR(_("Failed to allocate Memory!"));
+             continue;
+          }
 
-   find_part_proc(elm_object_item_text_get(parent_it), item_data->text,
-                  part_type);
+        pit->tag.type = Item_Type_Part;
+        pit->tag.idx = idx;
+        pit->name = strdup(name);
+        pit->type = enventor_object_part_type_get(enventor, name);
+        pit->git = git;
+        pit->it = elm_genlist_item_sorted_insert(nd->genlist,
+                                                 nd->part_itc,
+                                                 pit,
+                                                 git->it,
+                                                 ELM_GENLIST_ITEM_TREE,
+                                                 gl_comp_func,
+                                                 gl_part_selected_cb,
+                                                 pit);
+        git->parts = eina_list_append(git->parts, pit);
+     }
+
+   //3. Update parts
+   EINA_LIST_FOREACH_SAFE(git->parts, l, ll, pit)
+     {
+        //Remove them from the previous list.
+        if (pit->discarded)
+          {
+             git->parts = eina_list_remove_list(git->parts, l);
+             navigator_part_free(pit);
+             continue;
+          }
+
+        //Update parts states only if they are expanded.
+        if (!elm_genlist_item_expanded_get(pit->it)) continue;
+
+        states_update(nd, pit);
+     }
+
+   edje_edit_string_list_free(part_list);
 }
 
 static void
-parts_reload(navi_data *nd, Elm_Object_Item *group_it)
+part_expand(part_it *pit)
 {
-   Eina_List *l;
-   Elm_Object_Item *it;
+   if (elm_genlist_item_expanded_get(pit->it)) return;
 
-   //Remove Previous Parts
+   elm_genlist_item_expanded_set(pit->it, EINA_TRUE);
 
-   //FIXME: Maybe we could optimize if parts list hasn't been changed.
-   EINA_LIST_FREE(nd->part_items, it) elm_object_item_del(it);
-   nd->state_items = NULL;
-   edje_edit_string_list_free(nd->part_list);
+   states_update(pit->git->nd, pit);
 
-   //Append Parts
-   Evas_Object *enventor = base_enventor_get();
-   nd->part_list = enventor_object_parts_list_get(enventor);
-   char *name;
-   part_item_data *data;
-   Edje_Part_Type part_type;
+   //If auto contraction is enabled, then close other parts and programs
+   if (!(pit->git->nd->auto_contract)) return;
+
+   //Contract other part states
+   part_it *pit2;
+   Eina_List *l;
 
-   EINA_LIST_FOREACH(nd->part_list, l, name)
+   EINA_LIST_FOREACH(pit->git->parts, l, pit2)
      {
-        part_type = enventor_object_part_type_get(enventor, name);
-        data = malloc(sizeof(part_item_data));
-        data->text = name;
-        data->type = part_type;
-
-        it = elm_genlist_item_append(nd->genlist,
-                                     nd->part_itc,          /* item class */
-                                     data,                  /* item data */
-                                     group_it,              /* parent */
-                                     ELM_GENLIST_ITEM_NONE, /* item type */
-                                     gl_part_selected_cb,   /* select cb */
-                                     nd);                   /* select cb data 
*/
-        nd->part_items = eina_list_append(nd->part_items, it);
+        if (pit2 == pit) continue;
+        part_contract(pit2);
      }
+
+   //Contract programs
+   programs_contract(&pit->git->programs);
+}
+
+static void
+part_contract(part_it *pit)
+{
+   if (!elm_genlist_item_expanded_get(pit->it)) return;
+
+   elm_genlist_item_expanded_set(pit->it, EINA_FALSE);
+
+   navigator_states_clear(pit);
 }
 
 /* Group Related */
 
+static void
+group_update(navi_data *nd, group_it *git)
+{
+   parts_update(nd, git);
+   programs_update(nd, git);
+}
+
+static void
+group_expand(group_it *git)
+{
+   if (elm_genlist_item_expanded_get(git->it)) return;
+
+   elm_genlist_item_expanded_set(git->it, EINA_TRUE);
+
+   group_update(git->nd, git);
+
+   //If auto contraction is enabled, then close other parts
+   if (!(git->nd->auto_contract)) return;
+
+   //Contract other groups
+   group_it *git2;
+   Eina_List *l;
+
+   EINA_LIST_FOREACH(git->nd->groups, l, git2)
+     {
+        if (git2 == git) continue;
+        group_contract(git2);
+     }
+}
+
+static void
+group_contract(group_it *git)
+{
+   if (!elm_genlist_item_expanded_get(git->it)) return;
+
+   elm_genlist_item_expanded_set(git->it, EINA_FALSE);
+   navigator_parts_clear(git);
+   navigator_programs_clear(git);
+}
+
+static char *
+gl_group_text_get_cb(void *data, Evas_Object *obj EINA_UNUSED,
+                    const char *part EINA_UNUSED)
+{
+   group_it *git = data;
+   return strdup(git->name);
+}
+
 static Evas_Object *
 gl_group_content_get_cb(void *data EINA_UNUSED, Evas_Object *obj,
                         const char *part)
 {
-   if (strcmp("elm.swallow.icon", part)) return NULL;
-
-   Evas_Object *image = elm_image_add(obj);
-   elm_image_file_set(image, EDJE_PATH, "navi_group");
+   if (!strcmp("elm.swallow.icon", part))
+     {
+        Evas_Object *image = elm_image_add(obj);
+        elm_image_file_set(image, EDJE_PATH, "navi_group");
+        return image;
+     }
 
-   return image;
+   return NULL;
 }
 
 static void
 gl_group_selected_cb(void *data, Evas_Object *obj EINA_UNUSED, void 
*event_info)
 {
-   navi_data *nd = data;
-   if (nd->group_select_skip) return;
+   group_it *git = data;
+   find_group_proc(git->name);
+}
 
+static void
+gl_expand_request_cb(void *data, Evas_Object *obj, void *event_info)
+{
    Elm_Object_Item *it = event_info;
+   list_it *_it = (list_it *)elm_object_item_data_get(it);
 
-   states_remove(nd);
-   sub_programs_remove(nd);
+   switch(_it->type)
+     {
+      case Item_Type_Group:
+         group_expand((group_it*)_it);
+         break;
+      case Item_Type_Part:
+         part_expand((part_it*)_it);
+         break;
+      case Item_Type_Programs:
+         programs_expand((programs_it*)_it);
+         break;
+      default:
+         break;
+     }
+}
 
-   find_group_proc(elm_object_item_text_get(it));
+static void
+gl_contract_request_cb(void *data, Evas_Object *obj, void *event_info)
+{
+   Elm_Object_Item *it = event_info;
+   list_it *_it = (list_it *)elm_object_item_data_get(it);
+
+   switch(_it->type)
+     {
+      case Item_Type_Group:
+         group_contract((group_it*)_it);
+         break;
+      case Item_Type_Part:
+         part_contract((part_it*)_it);
+         break;
+      case Item_Type_Programs:
+         programs_contract((programs_it*)_it);
+         break;
+      default:
+         break;
+     }
 }
 
 /*****************************************************************************/
@@ -816,101 +1240,90 @@ edc_navigator_group_update(const char *cur_group)
      {
         Elm_Object_Item *it = elm_genlist_selected_item_get(nd->genlist);
         if (it) elm_genlist_item_selected_set(it, EINA_FALSE);
-        return;
      }
 
-   //If edc_navigator_reload() is not called yet?
-   if (!nd->group_list)
+   Eina_List *group_list = edje_file_collection_list(config_output_path_get());
+   unsigned int cur_group_len = 0;
+   group_it *git;
+   Eina_List *l, *ll;
+   char *name;
+   int idx = 0;
+
+   //1. Prepare for validation.
+   EINA_LIST_FOREACH(nd->groups, l, git)
      {
-        edc_navigator_reload(cur_group);
-        return;
+        git->discarded = EINA_TRUE;
+        git->tag.idx = IDX_MAX;
      }
 
-   Eina_List *l;
-   Elm_Object_Item *it;
-
-   //Find a current group item and select it.
-   Elm_Object_Item *group_it = NULL;
-   unsigned int cur_group_len = strlen(cur_group);
-
-   EINA_LIST_FOREACH(nd->group_items, l, it)
+   //2. New groups
+   EINA_LIST_FOREACH(group_list, l, name)
      {
-        const char *group_name = elm_object_item_data_get(it);
-        if (!group_name) continue;
+        idx++;
 
-        if (!strcmp(group_name, cur_group) &&
-            (strlen(group_name) == cur_group_len))
-          {
+        Eina_Bool new_group = EINA_TRUE;
 
-             //Skip a group selection callback because it leads the editor
-             //cursor jump on to the group area. But this group updation could
-             //be triggered in a various scenario. The cursor should be jumped
-             //only when user clicks a group item in the genlist.
-             nd->group_select_skip = EINA_TRUE;
-             elm_genlist_item_selected_set(it, EINA_TRUE);
-             nd->group_select_skip = EINA_FALSE;
-             group_it = it;
-             break;
+        //Check if it is existed?
+        EINA_LIST_FOREACH(nd->groups, ll, git)
+          {
+             if (!strcmp(name, git->name) &&
+                 (strlen(name) == strlen(git->name)))
+               {
+                  git->discarded = EINA_FALSE;
+                  new_group = EINA_FALSE;
+                  //update index of the item
+                  git->tag.idx = idx;
+                  break;
+               }
           }
-     }
-
-   //We couldn't find a group... ?
-   if (!group_it) return;
-
-   parts_reload(nd, group_it);
-   programs_reload(nd, group_it);
-}
-
-void
-edc_navigator_reload(const char *cur_group)
-{
-   navi_data *nd = g_nd;
-   if (!nd) return;
-
-   //Reset Navigator resource.
-
-   //FIXME: Maybe we could optimize if group list hasn't been changed.
-   nd->group_items = eina_list_free(nd->group_items);
-   nd->part_items = NULL;
-   nd->state_items = NULL;
-   nd->program_items = NULL;
+        if (!new_group) continue;
 
-   elm_genlist_clear(nd->genlist);
-   edje_file_collection_list_free(nd->group_list);
+        //Ok, this group is newly added.
+        group_it *git = calloc(1, sizeof(group_it));
+        if (!git)
+          {
+             EINA_LOG_ERR(_("Failed to allocate Memory!"));
+             continue;
+          }
 
-   if (!cur_group)
-     {
-        nd->group_list = NULL;
-        return;
+        git->tag.type = Item_Type_Group;
+        git->tag.idx = idx;
+        git->name = strdup(name);
+        git->nd = nd;
+        git->it = elm_genlist_item_sorted_insert(nd->genlist,
+                                                 nd->group_itc,
+                                                 git,
+                                                 NULL,
+                                                 ELM_GENLIST_ITEM_TREE,
+                                                 gl_comp_func,
+                                                 gl_group_selected_cb,
+                                                 git);
+        nd->groups = eina_list_append(nd->groups, git);
      }
 
-   nd->group_list = edje_file_collection_list(config_output_path_get());
-
-   //Update Group
-   Eina_List *l;
-   char *name;
-   Elm_Object_Item *it;
-   unsigned int cur_group_len = strlen(cur_group);
+   //3. Update groups
+   if (cur_group) cur_group_len = strlen(cur_group);
 
-   EINA_LIST_FOREACH(nd->group_list, l, name)
+   EINA_LIST_FOREACH_SAFE(nd->groups, l, ll, git)
      {
-        it = elm_genlist_item_append(nd->genlist,
-                                     nd->group_itc,         /* item class */
-                                     name,                  /* item data */
-                                     NULL,                  /* parent */
-                                     ELM_GENLIST_ITEM_NONE, /* item type */
-                                     gl_group_selected_cb,  /* select cb */
-                                     nd);                   /* select cb data 
*/
-
-        nd->group_items = eina_list_append(nd->group_items, it);
-
-        //Update a current group
-        if ((cur_group && !strcmp(name, cur_group)) &&
-            (strlen(name) == cur_group_len))
+        //remove them from the previous list.
+        if (git->discarded)
           {
-             edc_navigator_group_update(cur_group);
+             nd->groups = eina_list_remove_list(nd->groups, l);
+             navigator_group_free(git);
+             continue;
           }
+
+        //Update group parts only if they are expanded.
+        if (!elm_genlist_item_expanded_get(git->it)) continue;
+
+        //update only current group
+        if (cur_group && !strcmp(cur_group, git->name) &&
+            (cur_group_len == strlen(git->name)))
+            group_update(nd, git);
      }
+
+   edje_file_collection_list_free(group_list);
 }
 
 Evas_Object *
@@ -924,25 +1337,49 @@ edc_navigator_init(Evas_Object *parent)
      }
    g_nd = nd;
 
-   Evas_Object *genlist = elm_genlist_add(parent);
+   //Box
+   Evas_Object *box = elm_box_add(parent);
+   elm_object_focus_allow_set(box, EINA_FALSE);
+
+   //Genlist
+   Evas_Object *genlist = elm_genlist_add(box);
    elm_object_focus_allow_set(genlist, EINA_FALSE);
+   evas_object_smart_callback_add(genlist, "expand,request",
+                                  gl_expand_request_cb, nd);
+   evas_object_smart_callback_add(genlist, "contract,request",
+                                  gl_contract_request_cb, nd);
+   evas_object_size_hint_weight_set(genlist, EVAS_HINT_EXPAND,
+                                    EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(genlist, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_show(genlist);
+   elm_box_pack_end(box, genlist);
+
+   //Check for genlist option
+   Evas_Object *check = elm_check_add(box);
+   elm_object_text_set(check, "Automatic Contraction");
+   elm_check_state_set(check, EINA_FALSE);
+   evas_object_smart_callback_add(check, "changed", check_changed_cb, nd);
+   elm_object_focus_allow_set(check, EINA_FALSE);
+   evas_object_size_hint_weight_set(check, EVAS_HINT_EXPAND, 0);
+   evas_object_size_hint_align_set(check, 0.05, EVAS_HINT_FILL);
+   evas_object_show(check);
+   elm_box_pack_end(box, check);
 
    //Group Item Class
    Elm_Genlist_Item_Class *itc;
 
    itc = elm_genlist_item_class_new();
-   itc->item_style = "default";
-   itc->func.text_get = gl_text_get_cb;
+   itc->item_style = "tree_effect";
+   itc->func.text_get = gl_group_text_get_cb;
    itc->func.content_get = gl_group_content_get_cb;
 
    nd->group_itc = itc;
 
    //Part Item Class
    itc = elm_genlist_item_class_new();
-   itc->item_style = "default";
+   itc->item_style = "tree_effect";
    itc->func.text_get = gl_part_text_get_cb;
    itc->func.content_get = gl_part_content_get_cb;
-   itc->func.del = gl_part_del_cb;
 
    nd->part_itc = itc;
 
@@ -956,24 +1393,25 @@ edc_navigator_init(Evas_Object *parent)
 
    //Programs Item Class
    itc = elm_genlist_item_class_new();
-   itc->item_style = "default";
+   itc->item_style = "tree_effect";
    itc->func.text_get = gl_programs_text_get_cb;
    itc->func.content_get = gl_programs_content_get_cb;
-   itc->func.del = gl_programs_del_cb;
 
    nd->programs_itc = itc;
 
    //Program Item Class
    itc = elm_genlist_item_class_new();
    itc->item_style = "default";
-   itc->func.text_get = gl_text_get_cb;
+   itc->func.text_get = gl_program_text_get_cb;
    itc->func.content_get = gl_program_content_get_cb;
 
    nd->program_itc = itc;
 
+   nd->box = box;
    nd->genlist = genlist;
+   nd->check = check;
 
-   return genlist;
+   return box;
 }
 
 void
@@ -982,15 +1420,7 @@ edc_navigator_term(void)
    navi_data *nd = g_nd;
    if (!nd) return;
 
-   eina_list_free(nd->state_items);
-   eina_list_free(nd->part_items);
-   eina_list_free(nd->group_items);
-   eina_list_free(nd->program_items);
-
-   edje_file_collection_list_free(nd->group_list);
-   edje_edit_string_list_free(nd->part_list);
-   edje_edit_string_list_free(nd->state_list);
-   edje_edit_string_list_free(nd->program_list);
+   navigator_groups_clear(nd);
 
    elm_genlist_item_class_free(nd->group_itc);
    elm_genlist_item_class_free(nd->part_itc);
@@ -998,6 +1428,8 @@ edc_navigator_term(void)
    elm_genlist_item_class_free(nd->programs_itc);
    elm_genlist_item_class_free(nd->program_itc);
 
+   evas_object_del(nd->box);
+
    free(nd);
    g_nd = NULL;
 }
diff --git a/src/bin/main.c b/src/bin/main.c
index c2124c1..124ed08 100644
--- a/src/bin/main.c
+++ b/src/bin/main.c
@@ -419,7 +419,7 @@ enventor_cursor_group_changed_cb(void *data EINA_UNUSED,
 {
    const char *group_name = event_info;
    stats_edc_group_update(group_name);
-   base_edc_navigator_group_update(group_name);
+   base_edc_navigator_group_update();
 }
 
 static void
@@ -448,7 +448,7 @@ enventor_live_view_loaded_cb(void *data EINA_UNUSED, 
Evas_Object *obj,
    Evas_Coord w, h;
    config_view_size_get(&w, &h);
    enventor_object_live_view_size_set(obj, w, h);
-   base_edc_navigator_reload();
+   base_edc_navigator_group_update();
 }
 
 static void
@@ -517,7 +517,7 @@ enventor_live_view_updated_cb(void *data, Evas_Object *obj,
         ad->on_saving = EINA_FALSE;
      }
 
-   base_edc_navigator_group_update(stats_group_name_get());
+   base_edc_navigator_group_update();
 }
 
 static void
diff --git a/src/include/base_gui.h b/src/include/base_gui.h
index 965d02a..d64050a 100644
--- a/src/include/base_gui.h
+++ b/src/include/base_gui.h
@@ -27,5 +27,4 @@ void base_error_msg_set(const char *msg);
 void base_console_full_view(void);
 void base_file_browser_toggle(Eina_Bool toggle);
 void base_edc_navigator_toggle(Eina_Bool toggle);
-void base_edc_navigator_reload(void);
-void base_edc_navigator_group_update(const char *group_name);
+void base_edc_navigator_group_update(void);
diff --git a/src/include/edc_navigator.h b/src/include/edc_navigator.h
index 9e11b33..2f2f33f 100644
--- a/src/include/edc_navigator.h
+++ b/src/include/edc_navigator.h
@@ -1,4 +1,3 @@
 Evas_Object *edc_navigator_init(Evas_Object *parent);
 void edc_navigator_term(void);
-void edc_navigator_reload(const char *cur_group);
 void edc_navigator_group_update(const char *cur_group);

-- 


Reply via email to