Edje_Edit has been taught the basics of Embryo scripting.
authorsachiel <sachiel>
Thu, 2 Dec 2010 18:20:34 +0000 (18:20 +0000)
committersachiel <sachiel@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 2 Dec 2010 18:20:34 +0000 (18:20 +0000)
It is possible now to call a recompile of the script, which if it doesn't
fail, will also update the running Embryo VM. Saving the object, when opened
from a file compiled with a sufficiently new edje_cc (early this week, I think), will generate the source including the scripts in their right place.
It's still missing a proper report of errors during the script build, but that will come later.

git-svn-id: http://svn.enlightenment.org/svn/e/trunk/edje@55160 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/Edje_Edit.h
src/lib/edje_edit.c

index 1ee7b4f..f145163 100644 (file)
@@ -3381,13 +3381,74 @@ EAPI Eina_Bool edje_edit_program_filter_part_set(Evas_Object *obj, const char *p
  */ //@{
 
 /**
- * Get the script for the given object,
+ * Get the Embryo script for the group of the given object.
+ *
+ * Get the shared script for the group under edition. Shared script means
+ * the script {} block for the group, not counting what's in each program.
+ * It returns a malloc'd duplicate of the code, so users are free to modify
+ * the contents directly and they should remember to free() it when done.
+ * NULL will be returned if there's no script or an error occurred.
  *
  * @param obj Object being edited.
  *
- * @return The script name.
+ * @return The shared script code for this group.
+ */
+EAPI char *edje_edit_script_get(Evas_Object *obj);
+
+/**
+ * Set the code for the group script.
+ *
+ * Set the Embryo source code for the shared script of the edited group.
+ * Note that changing the code itself will not update the running VM, you
+ * need to call edje_edit_script_compile for it to get updated.
+ *
+ * @param obj The object being edited
+ * @param code The Embryo source
+ */
+EAPI void edje_edit_script_set(Evas_Object *obj, const char *code);
+
+/**
+ * Get the Embryo script for the given program.
+ *
+ * Get the script code for the given program. Like the group script, this
+ * function returns a duplicate of the code that the user can modify at will
+ * and must free when done using it.
+ * NULL will be returned if the program doesn't exist, doesn't have any
+ * script or is not of type script.
+ *
+ * @param obj Object being edited
+ * @param prog Program name
+ *
+ * @return The program script code
+ */
+EAPI char *edje_edit_script_program_get(Evas_Object *obj, const char *prog);
+
+/**
+ * Set the Embryo script for the given program.
+ *
+ * Set the Embryo source code for the program @p prog. It must be an
+ * existing program of type EDJE_ACTION_TYPE_SCRIPT, or the function
+ * will fail and do nothing.
+ * Note that changing the code itself will not update the running VM, you
+ * need to call edje_edit_script_compile for it to get updated.
+ *
+ * @param obj The object being edited
+ * @param prog The program name.
+ * @param code The Embryo source
+ */
+EAPI void edje_edit_script_program_set(Evas_Object *obj, const char *prog, const char *code);
+
+/**
+ * Compile the Embryo script for the given object
+ *
+ * If required, this function will process all script code for the group and
+ * build the bytecode, updating the running Embryo VM Program if the build
+ * is succesful.
+ *
+ * @param obj The object being edited
+ *
  */
-EAPI const char * edje_edit_script_get(Evas_Object *obj);
+EAPI Eina_Bool edje_edit_script_compile(Evas_Object *obj);
 
 
 //@}
index dfb22fd..16bfc68 100644 (file)
@@ -90,6 +90,28 @@ typedef struct _Edje_Edit Edje_Edit;
 struct _Edje_Edit
 {
    Edje base;
+
+   void *bytecode;
+   int bytecode_size;
+
+   char *embryo_source;
+   char *embryo_processed;
+   Eina_Hash *program_scripts;
+
+   Eina_Bool bytecode_dirty:1;
+   Eina_Bool embryo_source_dirty:1;
+   Eina_Bool all_dirty:1;
+   Eina_Bool script_need_recompile:1;
+};
+
+typedef struct _Program_Script Program_Script;
+struct _Program_Script
+{
+   int id;
+   char *code;
+   char *processed;
+   Eina_Bool dirty:1;
+   Eina_Bool delete_me:1;
 };
 
 static void _edje_edit_smart_add(Evas_Object *obj);
@@ -134,22 +156,60 @@ _edje_edit_smart_add(Evas_Object *obj)
 }
 
 static void
+_edje_edit_data_clean(Edje_Edit *eed)
+{
+   free(eed->bytecode);
+   free(eed->embryo_source);
+   free(eed->embryo_processed);
+
+   if (eed->program_scripts)
+     eina_hash_free(eed->program_scripts);
+
+   eed->bytecode = NULL;
+   eed->embryo_source = NULL;
+   eed->embryo_processed = NULL;
+   eed->program_scripts = NULL;
+   eed->bytecode_size = 0;
+   eed->bytecode_dirty = EINA_FALSE;
+   eed->embryo_source_dirty = EINA_FALSE;
+   eed->all_dirty = EINA_FALSE;
+   eed->script_need_recompile = EINA_FALSE;
+}
+
+static void
 _edje_edit_smart_del(Evas_Object *obj)
 {
-//   Edje_Edit *eed;
+   Edje_Edit *eed;
+
+   eed = evas_object_smart_data_get(obj);
+
+   _edje_edit_data_clean(eed);
 
-//   eed = evas_object_smart_data_get(obj);
    _edje_edit_parent_sc->base.del(obj);
 }
 
+static void
+_edje_edit_program_script_free(Program_Script *ps)
+{
+   free(ps->code);
+   free(ps->processed);
+   free(ps);
+}
+
 static Eina_Bool
 _edje_edit_smart_file_set(Evas_Object *obj, const char *file, const char *group)
 {
-//   Edje_Edit *eed;
+   Edje_Edit *eed;
+   Eet_File *ef;
+   char **keys, buf[64];
+   int count, i;
+   int len = strlen("edje/scripts/embryo/source/");
 
-//   eed = evas_object_smart_data_get(obj);
-   /* Nothing custom here yet, so we just call the parent function.
-    * TODO and maybes:
+   eed = evas_object_smart_data_get(obj);
+
+   _edje_edit_data_clean(eed);
+
+   /* TODO and maybes:
     *  * The whole point of this thing is keep track of stuff such as
     *    strings to free and who knows what, so we need to take care
     *    of those if the file/group changes.
@@ -162,7 +222,33 @@ _edje_edit_smart_file_set(Evas_Object *obj, const char *file, const char *group)
     *    (GROUP parts or BOX/TABLE items pointing to non-existent/renamed
     *    groups).
     */
-   return _edje_edit_parent_sc->file_set(obj, file, group);
+   if (!_edje_edit_parent_sc->file_set(obj, file, group))
+     return EINA_FALSE;
+
+   eed->program_scripts = eina_hash_int32_new((Eina_Free_Cb)_edje_edit_program_script_free);
+
+   ef = eet_open(file, EET_FILE_MODE_READ);
+
+   snprintf(buf, sizeof(buf), "edje/scripts/embryo/source/%i",
+            eed->base.collection->id);
+   eed->embryo_source = eet_read(ef, buf, &count);
+
+   snprintf(buf, sizeof(buf), "edje/scripts/embryo/source/%i/*",
+            eed->base.collection->id);
+   keys = eet_list(ef, buf, &count);
+   for (i = 0; i < count; i++)
+     {
+        Program_Script *ps;
+        int size;
+
+        ps = calloc(1, sizeof(Program_Script));
+
+        sscanf(keys[i] + len, "%*i/%i", &ps->id);
+        ps->code = eet_read(ef, keys[i], &size);
+        eina_hash_add(eed->program_scripts, &ps->id, ps);
+     }
+
+   return EINA_TRUE;
 }
 
 static void
@@ -205,39 +291,36 @@ _edje_part_description_find_byname(Edje_Edit *eed, const char *part, const char
 }
 
 static int
-_edje_image_id_find(Evas_Object *obj, const char *image_name)
+_edje_image_id_find(Edje_Edit *eed, const char *image_name)
 {
    unsigned int i;
 
-   GET_ED_OR_RETURN(-1);
-
-   if (!ed->file) return -1;
-   if (!ed->file->image_dir) return -1;
+   if (!eed->base.file) return -1;
+   if (!eed->base.file->image_dir) return -1;
 
    //printf("SEARCH IMAGE %s\n", image_name);
 
-   for (i = 0; i < ed->file->image_dir->entries_count; ++i)
-     if (ed->file->image_dir->entries[i].entry
-        && !strcmp(image_name, ed->file->image_dir->entries[i].entry))
+   for (i = 0; i < eed->base.file->image_dir->entries_count; ++i)
+     if (eed->base.file->image_dir->entries[i].entry
+        && !strcmp(image_name, eed->base.file->image_dir->entries[i].entry))
        return i;
 
    return -1;
 }
 
 static const char *
-_edje_image_name_find(Evas_Object *obj, int image_id)
+_edje_image_name_find(Edje_Edit *eed, int image_id)
 {
-   GET_ED_OR_RETURN(NULL);
-
-   if (!ed->file) return NULL;
-   if (!ed->file->image_dir) return NULL;
+   if (!eed->base.file) return NULL;
+   if (!eed->base.file->image_dir) return NULL;
 
    /* Special case for external image */
    if (image_id < 0) image_id = -image_id - 1;
 
    //printf("SEARCH IMAGE ID %d\n", image_id);
-   if ((unsigned int) image_id >= ed->file->image_dir->entries_count) return NULL;
-   return ed->file->image_dir->entries[image_id].entry;
+   if ((unsigned int) image_id >= eed->base.file->image_dir->entries_count)
+     return NULL;
+   return eed->base.file->image_dir->entries[image_id].entry;
 }
 
 static void
@@ -819,6 +902,14 @@ _edje_edit_group_references_update(Evas_Object *obj, const char *old_group_name,
    evas_object_del(part_obj);
 }
 
+static void
+_edje_edit_flag_script_dirty(Edje_Edit *eed, Eina_Bool all)
+{
+   eed->script_need_recompile = EINA_TRUE;
+   if (all)
+     eed->all_dirty = EINA_TRUE;
+}
+
 /*****************/
 /*  GENERAL API  */
 /*****************/
@@ -990,7 +1081,8 @@ edje_edit_group_del(Evas_Object *obj, const char *group_name)
    Edje_Part_Collection *g;
    Eina_List *l;
    Eet_File *eetf;
-   char buf[32];
+   char buf[64], **keys;
+   int count;
 
    eina_error_set(0);
 
@@ -1043,8 +1135,19 @@ edje_edit_group_del(Evas_Object *obj, const char *group_name)
            "for writing output", ed->file->path);
        return EINA_FALSE;
      }
-   snprintf(buf, sizeof(buf), "collections/%d", e->id);
+   snprintf(buf, sizeof(buf), "edje/collections/%d", e->id);
    eet_delete(eetf, buf);
+   snprintf(buf, sizeof(buf), "edje/scripts/embryo/compiled/%d", e->id);
+   eet_delete(eetf, buf);
+   snprintf(buf, sizeof(buf), "edje/scripts/embryo/source/%d", e->id);
+   eet_delete(eetf, buf);
+   snprintf(buf, sizeof(buf), "edje/scripts/embryo/source/%d/*", e->id);
+   keys = eet_list(eetf, buf, &count);
+   if (keys)
+     do {
+          count--;
+          eet_delete(eetf, keys[count]);
+     } while(count);
    eet_close(eetf);
 
    /* Free Group */
@@ -1922,6 +2025,8 @@ edje_edit_part_name_set(Evas_Object *obj, const char* part, const char* new_name
    _edje_if_string_free(ed, rp->part->name);
    rp->part->name = (char *)eina_stringshare_add(new_name);
 
+   _edje_edit_flag_script_dirty(eed, EINA_TRUE);
+
    return EINA_TRUE;
 }
 
@@ -2224,6 +2329,8 @@ edje_edit_part_del(Evas_Object *obj, const char* part)
 
    ce->count.part--;
 
+   _edje_edit_flag_script_dirty(eed, EINA_TRUE);
+
    return EINA_TRUE;
 }
 
@@ -2297,6 +2404,8 @@ edje_edit_part_restack_below(Evas_Object *obj, const char* part)
    if (rp->swallowed_object)
      evas_object_stack_above(rp->swallowed_object, rp->object);
 
+   _edje_edit_flag_script_dirty(eed, EINA_TRUE);
+
    return EINA_TRUE;
 }
 
@@ -2331,6 +2440,8 @@ edje_edit_part_restack_above(Evas_Object *obj, const char* part)
    if (rp->swallowed_object)
      evas_object_stack_above(rp->swallowed_object, rp->object);
 
+   _edje_edit_flag_script_dirty(eed, EINA_TRUE);
+
    return EINA_TRUE;
 }
 
@@ -4574,6 +4685,8 @@ edje_edit_image_del(Evas_Object *obj, const char* name)
    _edje_if_string_free(ed, de->entry);
    de->entry = NULL;
 
+   _edje_edit_flag_script_dirty(eed, EINA_TRUE);
+
    return EINA_TRUE;
 
 invalid_image:
@@ -4618,7 +4731,9 @@ edje_edit_image_id_get(Evas_Object *obj, const char *image_name)
 {
    eina_error_set(0);
 
-   return _edje_image_id_find(obj, image_name);
+   GET_ED_OR_RETURN(-1);
+
+   return _edje_image_id_find(eed, image_name);
 }
 
 EAPI Edje_Edit_Image_Comp
@@ -4693,7 +4808,7 @@ EAPI const char *
 edje_edit_state_image_get(Evas_Object *obj, const char *part, const char *state, double value)
 {
    Edje_Part_Description_Image *img;
-   char *image;
+   const char *image;
 
    eina_error_set(0);
 
@@ -4704,7 +4819,7 @@ edje_edit_state_image_get(Evas_Object *obj, const char *part, const char *state,
 
    img = (Edje_Part_Description_Image *) pd;
 
-   image = (char *)_edje_image_name_find(obj, img->image.id);
+   image = _edje_image_name_find(eed, img->image.id);
    if (!image) return NULL;
 
    //printf("GET IMAGE for %s [%s]\n", state, image);
@@ -4726,7 +4841,7 @@ edje_edit_state_image_set(Evas_Object *obj, const char *part, const char *state,
    if (rp->part->type != EDJE_PART_TYPE_IMAGE)
      return;
 
-   id = _edje_image_id_find(obj, image);
+   id = _edje_image_id_find(eed, image);
    //printf("SET IMAGE for %s [%s]\n", state, image);
 
    img = (Edje_Part_Description_Image *) pd;
@@ -4755,7 +4870,7 @@ edje_edit_state_tweens_list_get(Evas_Object *obj, const char *part, const char *
 
    for (i = 0; i < img->image.tweens_count; ++i)
      {
-       name = _edje_image_name_find(obj, img->image.tweens[i]->id);
+       name = _edje_image_name_find(eed, img->image.tweens[i]->id);
        //printf("   t: %s\n", name);
        tweens = eina_list_append(tweens, eina_stringshare_add(name));
      }
@@ -4778,7 +4893,7 @@ edje_edit_state_tween_add(Evas_Object *obj, const char *part, const char *state,
    if (rp->part->type != EDJE_PART_TYPE_IMAGE)
      return EINA_FALSE;
 
-   id = _edje_image_id_find(obj, tween);
+   id = _edje_image_id_find(eed, tween);
    if (id < EINA_FALSE) return 0;
 
    /* alloc Edje_Part_Image_Id */
@@ -4821,7 +4936,7 @@ edje_edit_state_tween_del(Evas_Object *obj, const char *part, const char *state,
 
    if (!img->image.tweens_count) return EINA_FALSE;
 
-   search = _edje_image_id_find(obj, tween);
+   search = _edje_image_id_find(eed, tween);
    if (search < 0) return EINA_FALSE;
 
    for (i = 0; i < img->image.tweens_count; ++i)
@@ -4935,6 +5050,21 @@ edje_edit_state_image_border_fill_set(Evas_Object *obj, const char *part, const
 /******************/
 /*  PROGRAMS API  */
 /******************/
+static int
+_edje_program_id_find(Edje_Edit *eed, const char *program)
+{
+   Edje_Program *epr;
+   int i;
+
+   for (i = 0; i < eed->base.table_programs_size; i++)
+     {
+        epr = eed->base.table_programs[i];
+        if (epr->name && !strcmp(epr->name, program))
+          return epr->id;
+     }
+   return -1;
+}
+
 static Edje_Program *
 _edje_program_get_byname(Evas_Object *obj, const char *prog_name)
 {
@@ -5049,6 +5179,7 @@ edje_edit_program_del(Evas_Object *obj, const char *prog)
    Edje_Program_After *pa;
    Edje_Part_Collection *pc;
    Edje_Program *p;
+   Program_Script *ps, *old_ps;
    int id, i;
    int old_id = -1;
 
@@ -5073,6 +5204,37 @@ edje_edit_program_del(Evas_Object *obj, const char *prog)
        ed->table_programs[epr->id]->id = epr->id;
      }
 
+   ps = eina_hash_find(eed->program_scripts, &id);
+   old_ps = eina_hash_find(eed->program_scripts, &old_id);
+   if (old_ps)
+     {
+        if (!ps)
+          {
+             ps = _alloc(sizeof(Program_Script));
+             ps->id = id;
+             eina_hash_add(eed->program_scripts, &id, ps);
+          }
+        else
+          {
+             free(ps->code);
+             free(ps->processed);
+             ps->processed = NULL;
+             ps->delete_me = EINA_FALSE;
+          }
+        ps->code = old_ps->code;
+        old_ps->code = NULL;
+        free(old_ps->processed);
+        old_ps->processed = NULL;
+        ps->dirty = EINA_TRUE;
+        old_ps->dirty = EINA_FALSE;
+        old_ps->delete_me = EINA_TRUE;
+     }
+   else if (ps)
+     {
+        ps->dirty = EINA_FALSE;
+        ps->delete_me = EINA_TRUE;
+     }
+
    //Free Edje_Program
    _edje_if_string_free(ed, epr->name);
    _edje_if_string_free(ed, epr->signal);
@@ -5105,7 +5267,10 @@ edje_edit_program_del(Evas_Object *obj, const char *prog)
             if (pa->id == old_id)
               pa->id = id;
             else if (pa->id == id)
-              p->after = eina_list_remove_list(p->after, l);
+               {
+                  p->after = eina_list_remove_list(p->after, l);
+                  free(pa);
+               }
          }
        /* check in targets */
        if (p->action == EDJE_ACTION_TYPE_ACTION_STOP)
@@ -5117,11 +5282,16 @@ edje_edit_program_del(Evas_Object *obj, const char *prog)
                  if (pt->id == old_id)
                    pt->id = id;
                  else if (pt->id == id)
-                   p->targets = eina_list_remove_list(p->targets, l);
+                    {
+                       p->targets = eina_list_remove_list(p->targets, l);
+                       free(pt);
+                    }
               }
          }
      }
 
+   _edje_edit_flag_script_dirty(eed, EINA_TRUE);
+
    return EINA_TRUE;
 }
 
@@ -5164,6 +5334,8 @@ edje_edit_program_name_set(Evas_Object *obj, const char *prog, const char* new_n
    _edje_if_string_free(ed, epr->name);
    epr->name = eina_stringshare_add(new_name);
 
+   _edje_edit_flag_script_dirty(eed, EINA_TRUE);
+
    return EINA_TRUE;
 }
 
@@ -5503,13 +5675,49 @@ edje_edit_program_action_get(Evas_Object *obj, const char *prog)
 EAPI Eina_Bool
 edje_edit_program_action_set(Evas_Object *obj, const char *prog, Edje_Action_Type action)
 {
+   Program_Script *ps;
+
    eina_error_set(0);
 
+   GET_ED_OR_RETURN(EINA_FALSE);
    GET_EPR_OR_RETURN(EINA_FALSE);
 
    //printf("SET ACTION for program: %s [%d]\n", prog, action);
    if (action >= EDJE_ACTION_TYPE_LAST) return EINA_FALSE;
 
+   if ((Edje_Action_Type)epr->action == action)
+     return EINA_TRUE;
+
+   if (action == EDJE_ACTION_TYPE_SCRIPT)
+     {
+        ps = eina_hash_find(eed->program_scripts, &epr->id);
+        if (!ps)
+          {
+             ps = _alloc(sizeof(Program_Script));
+             if (!ps)
+               return EINA_FALSE;
+          }
+        ps->id = epr->id;
+        ps->code = strdup("");
+        ps->dirty = EINA_TRUE;
+        ps->delete_me = EINA_FALSE;
+        eina_hash_set(eed->program_scripts, &ps->id, ps);
+        _edje_edit_flag_script_dirty(eed, EINA_FALSE);
+     }
+   if (epr->action == EDJE_ACTION_TYPE_SCRIPT)
+     {
+        ps = eina_hash_find(eed->program_scripts, &epr->id);
+        if (ps)
+          {
+             free(ps->code);
+             free(ps->processed);
+             ps->code = ps->processed = NULL;
+             ps->dirty = EINA_FALSE;
+             ps->delete_me = EINA_TRUE;
+             _edje_edit_flag_script_dirty(eed, EINA_FALSE);
+          }
+     }
+
    epr->action = action;
    return EINA_TRUE;
 }
@@ -5797,25 +6005,471 @@ edje_edit_program_api_description_set(Evas_Object *obj, const char *prog, const
 /*************************/
 /*  EMBRYO SCRIPTS  API  */
 /*************************/
-EAPI const char *
+EAPI char *
 edje_edit_script_get(Evas_Object *obj)
 {
-   Embryo_Program   *script = NULL;
-
    eina_error_set(0);
 
    GET_ED_OR_RETURN(NULL);
 
    if (!ed->collection) return NULL;
-   if (!ed->collection->script) return NULL;
+   if (!eed->embryo_source) return NULL;
+
+   return strdup(eed->embryo_source);
+}
+
+EAPI void
+edje_edit_script_set(Evas_Object *obj, const char *code)
+{
+   eina_error_set(0);
+
+   GET_ED_OR_RETURN();
+
+   free(eed->embryo_source);
+   free(eed->embryo_processed);
+
+   if (code)
+     eed->embryo_source = strdup(code);
+   else
+     eed->embryo_source = NULL;
+   eed->embryo_processed = NULL;
 
-   script = ed->collection->script;
+   eed->embryo_source_dirty = EINA_TRUE;
 
-   printf("Get Script [%p] %d\n", script, embryo_program_recursion_get(script));
+   _edje_edit_flag_script_dirty(eed, EINA_FALSE);
+}
+
+EAPI char *
+edje_edit_script_program_get(Evas_Object *obj, const char *prog)
+{
+   Program_Script *ps;
+
+   eina_error_set(0);
+
+   GET_ED_OR_RETURN(NULL);
+   GET_EPR_OR_RETURN(NULL);
+
+   if (epr->action != EDJE_ACTION_TYPE_SCRIPT)
+     return NULL;
+
+   ps = eina_hash_find(eed->program_scripts, prog);
+   if (!ps) /* mmm? it should be there, even if empty */
+     return NULL;
+
+   return ps->code ? strdup(ps->code) : NULL;
+}
+
+EAPI void
+edje_edit_script_program_set(Evas_Object *obj, const char *prog, const char *code)
+{
+   Program_Script *ps;
+
+   eina_error_set(0);
+
+   GET_ED_OR_RETURN();
+   GET_EPR_OR_RETURN();
+
+   if (epr->action != EDJE_ACTION_TYPE_SCRIPT)
+     return;
+
+   ps = eina_hash_find(eed->program_scripts, prog);
+   if (!ps) /* ???? how so? */
+     return;
+
+   free(ps->code);
+   free(ps->processed);
+
+   if (code)
+     ps->code = strdup(code);
+   else
+     ps->code = NULL;
+   ps->processed = NULL;
+   ps->dirty = EINA_TRUE;
 
-   return "Not yet complete...";
+   _edje_edit_flag_script_dirty(eed, EINA_FALSE);
 }
 
+static int
+__part_replace(Edje_Edit *eed, char *pcode, char *name)
+{
+   int id;
+
+   id = _edje_part_id_find((Edje *)eed, name);
+   if (id < 0)
+     return 0;
+   return eina_convert_itoa(id, pcode);
+}
+
+static int
+__program_replace(Edje_Edit *eed, char *pcode, char *name)
+{
+   int id;
+
+   id = _edje_program_id_find(eed, name);
+   if (id < 0)
+     return 0;
+   return eina_convert_itoa(id, pcode);
+}
+
+static int
+__group_replace(Edje_Edit *eed __UNUSED__, char *pcode, char *name)
+{
+   strcpy(pcode, name);
+   return strlen(name) + 1;
+}
+
+static int
+__image_replace(Edje_Edit *eed, char *pcode, char *name)
+{
+   int id;
+
+   id = _edje_image_id_find(eed, name);
+   if (id < 0)
+     return 0;
+   return eina_convert_itoa(id, pcode);
+}
+
+static char *
+_edje_edit_script_process(Edje_Edit *eed, char *code)
+{
+   char *pcode, *psrc, *pdst;
+   int codesize, pcodesize;
+   int quoted = 0, escaped = 0;
+   Eina_Bool success = EINA_TRUE;
+
+   codesize = strlen(code);
+   pcode = malloc(codesize + 1);
+   if (!pcode)
+     return NULL;
+
+   pcodesize = 0;
+   psrc = code;
+   pdst = pcode;
+   while (*psrc)
+     {
+        if (!quoted)
+          {
+             char *ptr = NULL;
+             int (*func)(Edje_Edit *, char *, char *);
+
+             if (*psrc == 'P')
+               {
+                  if (!strncmp(psrc, "PART:\"", 6))
+                    {
+                       psrc += 6;
+                       ptr = psrc;
+                       func = __part_replace;
+                    }
+                  else if (!strncmp(psrc, "PROGRAM:\"", 9))
+                    {
+                       psrc += 9;
+                       ptr = psrc;
+                       func = __program_replace;
+                    }
+               }
+             else if (*psrc == 'G')
+               {
+                  if (!strncmp(psrc, "GROUP:\"", 7))
+                    {
+                       psrc += 7;
+                       ptr = psrc;
+                       func = __group_replace;
+                    }
+               }
+             else if (*psrc == 'I')
+               {
+                  if (!strncmp(psrc, "IMAGE:\"", 7))
+                    {
+                       psrc += 7;
+                       ptr = psrc;
+                       func = __image_replace;
+                    }
+               }
+             else if (*psrc == '#')
+               {
+                  while (*psrc)
+                    if (*psrc == '\n')
+                      break;
+                  continue;
+               }
+             else if (*psrc == '\"')
+               quoted = 1;
+
+             if (ptr)
+               {
+                  int i = 0, inesc = 0;
+                  char *name;
+                  while (*psrc)
+                    {
+                       if (!inesc)
+                         {
+                            if (*psrc == '\\')
+                              inesc = 1;
+                            else if (*psrc == '\"')
+                              {
+                                 /* string concatenation as in "foo""bar" */
+                                 if (*(psrc + 1) != '\"')
+                                   {
+                                      psrc++;
+                                      break;
+                                   }
+                                 else
+                                   psrc++;
+                              }
+                         }
+                       else
+                         inesc = 0;
+                       psrc++;
+                    }
+                  name = alloca(psrc - ptr);
+                  inesc = 0;
+                  while (*ptr)
+                    {
+                       if (!inesc)
+                         {
+                            if (*ptr == '\\')
+                              inesc = 1;
+                            else if (*ptr == '\"')
+                              {
+                                 if (*(ptr + 1) == '\"')
+                                   ptr++;
+                                 else
+                                   {
+                                      name[i] = 0;
+                                      break;
+                                   }
+                              }
+                            else
+                              {
+                                 name[i] = *ptr;
+                                 name[i + 1] = 0;
+                                 i++;
+                              }
+                         }
+                       else
+                         inesc = 0;
+                       ptr++;
+                    }
+                  i = func(eed, pdst, name);
+                  if (!i)
+                    {
+                       /* something was not found, report it, keep track of
+                        * it to inform of non-existant referenced things
+                        * and continue processing to find all of those errors
+                        */
+                       success = EINA_FALSE;
+                    }
+                  else
+                    {
+                       pcodesize += i;
+                       pdst += i;
+                    }
+                  /* replaced reference for the right value, now go
+                   * to the next iteration */
+                  continue;
+               }
+          }
+        else
+          {
+             if (!escaped)
+               {
+                  if (*psrc == '\"')
+                    quoted = 0;
+                  else if (*psrc == '\\')
+                    escaped = 1;
+               }
+             else if (escaped)
+               escaped = 0;
+          }
+        *pdst = *psrc;
+        pdst++;
+        psrc++;
+        pcodesize++;
+     }
+
+   if (!success)
+     {
+        free(pcode);
+        return NULL;
+     }
+
+   if (pcodesize < codesize)
+     pcode = realloc(pcode, pcodesize + 1);
+   pcode[pcodesize] = 0;
+
+   return pcode;
+}
+
+static Eina_Bool
+_edje_edit_embryo_rebuild(Edje_Edit *eed)
+{
+   FILE *f;
+   int fd, size, ret;
+   const char *tmp_dir;
+   char tmp_in[PATH_MAX];
+   char tmp_out[PATH_MAX];
+   char buf[4096];
+   Eina_Iterator *it;
+   Program_Script *ps;
+   Edje_Part_Collection *edc;
+   Eina_Bool success = EINA_TRUE; /* we are optimists! */
+
+#ifdef HAVE_EVIL
+   tmp_dir = evil_tmpdir_get();
+#else
+   tmp_dir = "/tmp";
+#endif
+
+   snprintf(tmp_in, sizeof(tmp_in), "%s/edje_edit.sma-tmp-XXXXXX", tmp_dir);
+   snprintf(tmp_out, sizeof(tmp_out), "%s/edje_edit.amx-tmp-XXXXXX", tmp_dir);
+
+   fd = mkstemp(tmp_in);
+   if (fd < 0)
+     return EINA_FALSE; /* FIXME: report something */
+
+   f = fdopen(fd, "w");
+   if (!f)
+     {
+        close(fd);
+        unlink(tmp_in);
+        return EINA_FALSE;
+     }
+
+   fprintf(f, "#include <edje>\n");
+   if (eed->embryo_source)
+     {
+        if (eed->all_dirty)
+          {
+             free(eed->embryo_processed);
+             eed->embryo_processed = NULL;
+          }
+        if (!eed->embryo_processed)
+          eed->embryo_processed = _edje_edit_script_process(eed,
+                                                            eed->embryo_source);
+        if (!eed->embryo_processed)
+          {
+             /* oops.. an error finding references parts or something.
+              * we could flag it and do some lighter processing of the
+              * rest of the scripts, in order to find all the errors of
+              * this kind and report them at once, but knowing already
+              * that the script will not compile we can avoid some work
+              */
+             success = EINA_FALSE;
+          }
+        else
+          fprintf(f, eed->embryo_processed);
+     }
+
+   it = eina_hash_iterator_data_new(eed->program_scripts);
+   EINA_ITERATOR_FOREACH(it, ps)
+     {
+        if (ps->delete_me)
+          continue;
+        if (eed->all_dirty)
+          {
+             free(ps->processed);
+             ps->processed = NULL;
+          }
+        if (!ps->processed)
+          ps->processed = _edje_edit_script_process(eed, ps->code);
+        if (!ps->processed)
+          {
+             /* oops.. an error finding references parts or something.
+              * we could flag it and do some lighter processing of the
+              * rest of the scripts, in order to find all the errors of
+              * this kind and report them at once, but knowing already
+              * that the script will not compile we can avoid some work
+              */
+             success = EINA_FALSE;
+             continue;
+          }
+        fprintf(f, "public _p%i(sig[], src[]) {\n", ps->id);
+        fprintf(f, ps->processed);
+        fprintf(f, "}\n");
+     }
+   eina_iterator_free(it);
+
+   fclose(f);
+
+   fd = mkstemp(tmp_out);
+   if (fd < 0)
+     {
+        success = EINA_FALSE;
+        goto almost_out;
+     }
+
+   snprintf(buf, sizeof(buf), "embryo_cc -i %s/include -o %s %s",
+            PACKAGE_DATA_DIR, tmp_out, tmp_in);
+   ret = system(buf);
+
+   if ((ret < 0) || (ret > 1))
+     {
+        success = EINA_FALSE;
+        close(fd);
+        goto the_way_out;
+     }
+
+   f = fdopen(fd, "rb");
+   if (!f)
+     {
+        success = EINA_FALSE;
+        close(fd);
+        goto the_way_out;
+     }
+
+   fseek(f, 0, SEEK_END);
+   size = ftell(f);
+   rewind(f);
+
+   free(eed->bytecode);
+   if (size > 0)
+     {
+        eed->bytecode = malloc(size);
+        if (!eed->bytecode)
+          {
+             success = EINA_FALSE;
+             goto the_way_out;
+          }
+        if (fread(eed->bytecode, size, 1, f) != 1)
+          {
+             success = EINA_FALSE;
+             goto the_way_out;
+          }
+     }
+   else
+     eed->bytecode = NULL; /* correctness mostly, I don't see why we
+                              would get a 0 sized program */
+
+   eed->bytecode_size = size;
+   eed->bytecode_dirty = EINA_TRUE;
+   eed->script_need_recompile = EINA_FALSE;
+   eed->all_dirty = EINA_FALSE;
+
+   edc = eed->base.collection;
+   embryo_program_free(edc->script);
+   edc->script = embryo_program_new(eed->bytecode, eed->bytecode_size);
+   _edje_embryo_script_init(edc);
+   _edje_var_init((Edje *)eed);
+
+the_way_out:
+   fclose(f);
+   unlink(tmp_out);
+almost_out:
+   unlink(tmp_in);
+
+   return success;
+}
+
+EAPI Eina_Bool
+edje_edit_script_compile(Evas_Object *obj)
+{
+   GET_ED_OR_RETURN(EINA_FALSE);
+
+   if (!eed->script_need_recompile)
+     return EINA_TRUE;
+
+   return _edje_edit_embryo_rebuild(eed);
+}
 
 /***************************/
 /*  EDC SOURCE GENERATION  */
@@ -5893,9 +6547,12 @@ _edje_generate_source_of_program(Evas_Object *obj, const char *program, Eina_Str
    char *data;
    Eina_Bool ret = EINA_TRUE;
    const char *api_name, *api_description;
+   Edje_Program *epr;
 
    GET_ED_OR_RETURN(EINA_FALSE);
 
+   epr = _edje_program_get_byname(obj, program);
+
    BUF_APPENDF(I3"program { name: \"%s\";\n", program);
 
    /* Signal */
@@ -5936,6 +6593,19 @@ _edje_generate_source_of_program(Evas_Object *obj, const char *program, Eina_Str
                edje_edit_string_free(s2);
          }
        break;
+     case EDJE_ACTION_TYPE_SCRIPT:
+          {
+             Program_Script *ps;
+
+             ps = eina_hash_find(eed->program_scripts, &epr->id);
+             if (ps && !ps->delete_me)
+               {
+                  BUF_APPEND(I4"script {\n");
+                  BUF_APPEND(ps->code);
+                  BUF_APPEND(I4"}\n");
+               }
+          }
+        break;
      //TODO Support Drag
      //~ case EDJE_ACTION_TYPE_DRAG_VAL_SET:
        //~ eina_strbuf_append(buf, I4"action: DRAG_VAL_SET TODO;\n");
@@ -6134,7 +6804,7 @@ _edje_generate_source_of_state(Evas_Object *obj, const char *part, const char *s
 
        BUF_APPEND(I5"image {\n");
 
-       image_name = _edje_image_name_find(obj, img->image.id);
+       image_name = _edje_image_name_find(eed, img->image.id);
        if (image_name)
          BUF_APPENDF(I6"normal: \"%s\";\n", image_name);
 
@@ -6375,17 +7045,30 @@ _edje_generate_source_of_part(Evas_Object *obj, Edje_Part *ep, Eina_Strbuf *buf)
 static Eina_Bool
 _edje_generate_source_of_group(Edje *ed, Edje_Part_Collection_Directory_Entry *pce, Eina_Strbuf *buf)
 {
+   Edje_Edit *eed;
+   Eet_File *ef;
    Evas_Object *obj;
    Eina_List *l, *ll;
    unsigned int i;
    int w, h;
    char *data;
    const char *group = pce->entry;
+   Edje_Part_Collection *pc;
    Eina_Bool ret = EINA_TRUE;
 
    obj = edje_edit_object_add(ed->evas);
    if (!edje_object_file_set(obj, ed->file->path, group)) return EINA_FALSE;
 
+   ef = eet_open(ed->file->path, EET_FILE_MODE_READ);
+   if (!ef)
+     {
+        evas_object_del(obj);
+        return EINA_FALSE;
+     }
+
+   eed = evas_object_smart_data_get(obj);
+   pc = eed->base.collection;
+
    BUF_APPENDF(I1"group { name: \"%s\";\n", group);
    //TODO Support alias:
    w = edje_edit_group_min_w_get(obj);
@@ -6398,13 +7081,13 @@ _edje_generate_source_of_group(Edje *ed, Edje_Part_Collection_Directory_Entry *p
       BUF_APPENDF(I2"max: %d %d;\n", w, h);
 
    /* Data */
-   if (pce->ref->data)
+   if (pc->data)
      {
         Eina_Iterator *it;
         Eina_Hash_Tuple *tuple;
         BUF_APPEND(I2"data {\n");
 
-        it = eina_hash_iterator_tuple_new(pce->ref->data);
+        it = eina_hash_iterator_tuple_new(pc->data);
 
         if (!it)
           {
@@ -6420,14 +7103,19 @@ _edje_generate_source_of_group(Edje *ed, Edje_Part_Collection_Directory_Entry *p
         BUF_APPEND(I2"}\n");
      }
 
-   //TODO Support script
+   if (eed->embryo_source)
+     {
+        BUF_APPEND(I2"script {\n");
+        BUF_APPEND(eed->embryo_source);
+        BUF_APPEND(I2"}\n");
+     }
 
    /* Parts */
    BUF_APPEND(I2"parts {\n");
-   for (i = 0; i < pce->ref->parts_count; i++)
+   for (i = 0; i < pc->parts_count; i++)
      {
         Edje_Part *ep;
-        ep = pce->ref->parts[i];
+        ep = pc->parts[i];
         ret &= _edje_generate_source_of_part(obj, ep, buf);
      }
    BUF_APPEND(I2"}\n");//parts
@@ -6447,7 +7135,7 @@ _edje_generate_source_of_group(Edje *ed, Edje_Part_Collection_Directory_Entry *p
        BUF_APPEND(I2 "}\n");
        edje_edit_string_list_free(ll);
      }
-   BUF_APPEND("   }\n");//group
+   BUF_APPEND(I1"}\n");//group
 
    if (!ret)
      {
@@ -6456,6 +7144,7 @@ _edje_generate_source_of_group(Edje *ed, Edje_Part_Collection_Directory_Entry *p
         return EINA_FALSE;
      }
 
+   eet_close(ef);
    evas_object_del(obj);
    return ret;
 }
@@ -6867,6 +7556,57 @@ _edje_edit_internal_save(Evas_Object *obj, int current_only)
          }
      }
 
+   if (eed->bytecode_dirty || eed->script_need_recompile)
+     {
+        char buf[64];
+        Eina_Iterator *it;
+        Program_Script *ps;
+        Eina_List *deathnote = NULL;
+
+        if (eed->bytecode_dirty)
+          {
+             snprintf(buf, sizeof(buf), "edje/scripts/embryo/compiled/%i",
+                      ed->collection->id);
+             eet_write(eetf, buf, eed->bytecode, eed->bytecode_size, 1);
+             free(eed->bytecode);
+             eed->bytecode = NULL;
+             eed->bytecode_size = 0;
+             eed->bytecode_dirty = EINA_FALSE;
+          }
+
+        if (eed->embryo_source_dirty)
+          {
+             snprintf(buf, sizeof(buf), "edje/scripts/embryo/source/%i",
+                      ed->collection->id);
+             eet_write(eetf, buf, eed->embryo_source,
+                       strlen(eed->embryo_source) +1, 1);
+             eed->embryo_source_dirty = EINA_FALSE;
+          }
+
+        it = eina_hash_iterator_data_new(eed->program_scripts);
+        EINA_ITERATOR_FOREACH(it, ps)
+          {
+             if (ps->dirty)
+               {
+                  snprintf(buf, sizeof(buf), "edje/scripts/embryo/source/%i/%i",
+                           ed->collection->id, ps->id);
+                  eet_write(eetf, buf, ps->code, strlen(ps->code) + 1, 1);
+                  ps->dirty = EINA_FALSE;
+               }
+             else if (ps->delete_me)
+               {
+                  snprintf(buf, sizeof(buf), "edje/scripts/embryo/source/%i/%i",
+                           ed->collection->id, ps->id);
+                  eet_delete(eetf, buf);
+                  deathnote = eina_list_append(deathnote, ps);
+               }
+          }
+        eina_iterator_free(it);
+
+        EINA_LIST_FREE(deathnote, ps)
+           eina_hash_del(eed->program_scripts, &ps->id, ps);
+     }
+
    if (!_edje_edit_source_save(eetf, obj))
      {
        eet_close(eetf);