diff options
Diffstat (limited to 'src/bin/exactness/inspect.c')
-rw-r--r-- | src/bin/exactness/inspect.c | 1653 |
1 files changed, 1653 insertions, 0 deletions
diff --git a/src/bin/exactness/inspect.c b/src/bin/exactness/inspect.c new file mode 100644 index 0000000000..54f6627f22 --- /dev/null +++ b/src/bin/exactness/inspect.c @@ -0,0 +1,1653 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifndef EFL_BETA_API_SUPPORT +#define EFL_BETA_API_SUPPORT +#endif +#ifndef EFL_EO_API_SUPPORT +#define EFL_EO_API_SUPPORT +#endif +#include <Ecore.h> +#include <Ecore_Getopt.h> +#include <Ecore_Evas.h> +#include <Elementary.h> +#include <Exactness.h> +#include <Efl_Ui.h> + +#include "exactness_private.h" + +#define LDIFF(x) "<b><color=#F0F>"#x"</color></b>" +#define RDIFF(x) "<b><color=#0FF>"#x"</color></b>" + +typedef enum +{ + EX_FONTS_DIR, + EX_SCENARIO, + EX_IMAGE, + EX_OBJ_INFO +} _Data_Type; + +typedef struct +{ + void *p1; + void *p2; + _Data_Type dt; +} _Compare_Item_Data; + +typedef struct +{ + void *ex_parent; + Eo *gl_item; +} _Item_Info; + +static Eo *_main_box = NULL; +static Eina_List *_gls = NULL; +static Eina_List *_units = NULL; +static Eo *_comp_selected_item = NULL; + +static Elm_Genlist_Item_Class *_grp_itc = NULL, *_scn_itc = NULL, *_img_itc = NULL; +static Elm_Genlist_Item_Class *_objs_itc = NULL, *_obj_itc = NULL; + +static Eina_Hash *_item_infos_hash = NULL; + +static Eina_Bool _show_only_diffs = EINA_FALSE; +static Eina_List *_comp_vvs = NULL; + +static Eina_List *_modified_units = NULL; + +static const char * +_action_name_get(Exactness_Action *act) +{ + if (!act) return NULL; + switch(act->type) + { + case EXACTNESS_ACTION_MOUSE_IN: return "Mouse In"; + case EXACTNESS_ACTION_MOUSE_OUT: return "Mouse Out"; + case EXACTNESS_ACTION_MOUSE_WHEEL: return "Mouse Wheel"; + case EXACTNESS_ACTION_MULTI_DOWN: return "Multi Down"; + case EXACTNESS_ACTION_MULTI_UP: return "Multi Up"; + case EXACTNESS_ACTION_MULTI_MOVE: return "Multi Move"; + case EXACTNESS_ACTION_KEY_DOWN: return "Key Down"; + case EXACTNESS_ACTION_KEY_UP: return "Key Up"; + case EXACTNESS_ACTION_TAKE_SHOT: return "Take shot"; + case EXACTNESS_ACTION_EFL_EVENT: return "EFL Event"; + case EXACTNESS_ACTION_CLICK_ON: return "Click On"; + case EXACTNESS_ACTION_STABILIZE: return "Stabilize"; + default: return NULL; + } +} + +static int +_event_struct_len_get(Exactness_Action_Type type) +{ + switch(type) + { + case EXACTNESS_ACTION_MOUSE_WHEEL: + return sizeof(Exactness_Action_Mouse_Wheel); + case EXACTNESS_ACTION_MULTI_DOWN: + case EXACTNESS_ACTION_MULTI_UP: + return sizeof(Exactness_Action_Multi_Event); + case EXACTNESS_ACTION_MULTI_MOVE: + return sizeof(Exactness_Action_Multi_Move); + case EXACTNESS_ACTION_KEY_DOWN: + case EXACTNESS_ACTION_KEY_UP: + return sizeof(Exactness_Action_Key_Down_Up); + case EXACTNESS_ACTION_EFL_EVENT: + return sizeof(Exactness_Action_Efl_Event); + case EXACTNESS_ACTION_CLICK_ON: + return sizeof(Exactness_Action_Click_On); + default: return 0; + } +} + +static void +_action_specific_info_get(const Exactness_Action *act, char output[1024]) +{ + switch(act->type) + { + case EXACTNESS_ACTION_MOUSE_WHEEL: + { + Exactness_Action_Mouse_Wheel *t = act->data; + sprintf(output, "Direction %d Z %d", t->direction, t->z); + break; + } + case EXACTNESS_ACTION_MULTI_UP: case EXACTNESS_ACTION_MULTI_DOWN: + { + Exactness_Action_Multi_Event *t = act->data; + if (!t->d) + sprintf(output, "Button %d Flags %d", t->b, t->flags); + else + sprintf(output, "D %d X %d Y %d Rad %f RadX %f RadY %f Pres %f Ang %f FX %f FY %f Flags %d", + t->d, t->x, t->y, t->rad, t->radx, t->rady, t->pres, t->ang, t->fx, t->fy, t->flags); + break; + } + case EXACTNESS_ACTION_MULTI_MOVE: + { + Exactness_Action_Multi_Move *t = act->data; + if (!t->d) + sprintf(output, "X %d Y %d", t->x, t->y); + else + sprintf(output, "D %d X %d Y %d Rad %f RadX %f RadY %f Pres %f Ang %f FX %f FY %f", + t->d, t->x, t->y, t->rad, t->radx, t->rady, t->pres, t->ang, t->fx, t->fy); + break; + } + case EXACTNESS_ACTION_KEY_UP: case EXACTNESS_ACTION_KEY_DOWN: + { + Exactness_Action_Key_Down_Up *t = act->data; + sprintf(output, "Keyname %s Key %s String %s Compose %s Keycode %d", + t->keyname, t->key, t->string, t->compose, t->keycode); + break; + } + case EXACTNESS_ACTION_EFL_EVENT: + { + Exactness_Action_Efl_Event *t = act->data; + sprintf(output, "Widget %s Event %s", t->wdg_name, t->event_name); + break; + } + case EXACTNESS_ACTION_CLICK_ON: + { + Exactness_Action_Click_On *t = act->data; + sprintf(output, "Widget %s", t->wdg_name); + break; + } + default: + { + output[0] = '\0'; + break; + } + } +} + +static Eina_Bool +_is_hook_duplicate(const Exactness_Action *cur_act, const Exactness_Action *prev_act) +{ + if (!prev_act) return EINA_FALSE; + if (cur_act->type == prev_act->type) + { + int len = _event_struct_len_get(cur_act->type); + return (!len || !memcmp(cur_act->data, prev_act->data, len)); + } + return EINA_FALSE; +} + +static Eina_Bool +_are_scenario_entries_different(Exactness_Action *act1, Exactness_Action *act2) +{ + if (!act1 ^ !act2) return EINA_TRUE; + if (act1->type != act2->type) return EINA_TRUE; + switch(act1->type) + { + case EXACTNESS_ACTION_MOUSE_WHEEL: + return !!memcmp(act1->data, act2->data, sizeof(Exactness_Action_Mouse_Wheel)); + case EXACTNESS_ACTION_MULTI_DOWN: case EXACTNESS_ACTION_MULTI_UP: + return !!memcmp(act1->data, act2->data, sizeof(Exactness_Action_Multi_Event)); + case EXACTNESS_ACTION_MULTI_MOVE: + return !!memcmp(act1->data, act2->data, sizeof(Exactness_Action_Multi_Move)); + case EXACTNESS_ACTION_KEY_UP: case EXACTNESS_ACTION_KEY_DOWN: + return !!memcmp(act1->data, act2->data, sizeof(Exactness_Action_Key_Down_Up)); + case EXACTNESS_ACTION_EFL_EVENT: + { + Exactness_Action_Efl_Event *e1 = act1->data; + Exactness_Action_Efl_Event *e2 = act2->data; + return (!!strcmp(e1->wdg_name, e2->wdg_name) || + !!strcmp(e1->event_name, e2->event_name)); + } + case EXACTNESS_ACTION_CLICK_ON: + { + Exactness_Action_Click_On *e1 = act1->data; + Exactness_Action_Click_On *e2 = act2->data; + return (!!strcmp(e1->wdg_name, e2->wdg_name)); + } + default: + return EINA_FALSE; + } + return EINA_FALSE; +} + +static Eina_Bool +_are_images_different(Exactness_Image *e_img1, Exactness_Image *e_img2) +{ + unsigned int w, h; + int *pxs1 = NULL; + int *pxs2 = NULL; + if (!e_img1 ^ !e_img2) return EINA_TRUE; + if (e_img1->w != e_img2->w) return EINA_TRUE; + if (e_img1->h != e_img2->h) return EINA_TRUE; + pxs1 = e_img1->pixels; + pxs2 = e_img2->pixels; + for (w = 0; w < e_img1->w; w++) + { + for (h = 0; h < e_img1->h; h++) + { + if (pxs1[h * e_img1->w + w] != pxs2[h * e_img1->w + w]) + return EINA_TRUE; + } + } + return EINA_FALSE; +} + +static Eina_Bool +_are_objs_different(Exactness_Object *e_obj1, Exactness_Object *e_obj2, Eina_Bool check_objs) +{ + if (!e_obj1 ^ !e_obj2) return EINA_TRUE; + Eina_List *itr1 = e_obj1->children; + Eina_List *itr2 = e_obj2->children; + if (check_objs && + (strcmp(e_obj1->kl_name, e_obj2->kl_name) || + e_obj1->x != e_obj2->x || e_obj1->y != e_obj2->y || + e_obj1->w != e_obj2->w || e_obj1->h != e_obj2->h)) return EINA_TRUE; + while (itr1 || itr2) + { + if ((!itr1) ^ (!itr2)) return EINA_TRUE; + e_obj1 = eina_list_data_get(itr1); + e_obj2 = eina_list_data_get(itr2); + + if (_are_objs_different(e_obj1, e_obj2, EINA_TRUE)) return EINA_TRUE; + + itr1 = eina_list_next(itr1); + itr2 = eina_list_next(itr2); + } + return EINA_FALSE; +} + +static Eina_Bool +_are_objs_trees_different(Exactness_Objects *e_objs1, Exactness_Objects *e_objs2) +{ + if (!e_objs1 ^ !e_objs2) return EINA_TRUE; + Eina_List *itr1 = e_objs1->objs; + Eina_List *itr2 = e_objs2->objs; + Exactness_Object *e_obj1, *e_obj2; + while (itr1 || itr2) + { + if ((!itr1) ^ (!itr2)) return EINA_TRUE; + e_obj1 = eina_list_data_get(itr1); + e_obj2 = eina_list_data_get(itr2); + + if (_are_objs_different(e_obj1, e_obj2, EINA_TRUE)) return EINA_TRUE; + + itr1 = eina_list_next(itr1); + itr2 = eina_list_next(itr2); + } + return EINA_FALSE; +} + +static void +_win_del(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + efl_exit(0); /* exit the program's main loop that runs in elm_run() */ +} + +static void +_gui_win_create() +{ + Eo *win, *bg; + + elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); + win = elm_win_add(NULL, "Window", ELM_WIN_BASIC); + evas_object_smart_callback_add(win, "delete,request", _win_del, NULL); + elm_win_maximized_set(win, EINA_TRUE); + elm_win_autodel_set(win, EINA_TRUE); + elm_win_title_set(win, "Exactness Inspector"); + efl_gfx_entity_size_set(win, EINA_SIZE2D(1000, 800)); + + bg = elm_bg_add(win); + evas_object_size_hint_weight_set(bg, 1.000000, 1.000000); + efl_gfx_entity_visible_set(bg, EINA_TRUE); + elm_win_resize_object_add(win, bg); + + _main_box = elm_box_add(win); + elm_box_horizontal_set(_main_box, EINA_TRUE); + elm_box_homogeneous_set(_main_box, EINA_TRUE); + evas_object_size_hint_weight_set(_main_box, 1.000000, 1.000000); + efl_gfx_entity_visible_set(_main_box, EINA_TRUE); + elm_win_resize_object_add(win, _main_box); + + efl_gfx_entity_visible_set(win, EINA_TRUE); +} + +static char * +_grp_text_get(void *data, Evas_Object *gl, const char *part EINA_UNUSED) +{ + char buf[256]; + const char *str = NULL; + Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare"); + _Data_Type dt = (_Data_Type) data; + switch (dt) + { + case EX_FONTS_DIR: + { + char buf2[256]; + if (!compare) + { + Exactness_Unit *unit = efl_key_data_get(gl, "unit"); + sprintf(buf2, "Fonts directory: %s", unit->fonts_path?unit->fonts_path:"None"); + } + else + { + Eo *gl1 = eina_list_nth(_gls, 0); + Eo *gl2 = eina_list_nth(_gls, 1); + Exactness_Unit *unit1 = efl_key_data_get(gl1, "unit"); + Exactness_Unit *unit2 = efl_key_data_get(gl2, "unit"); + if (!!unit1->fonts_path ^ !!unit2->fonts_path) + sprintf(buf2, "Fonts directory comparison: XXXXX"); + else if (!strcmp(unit1->fonts_path, unit2->fonts_path)) + sprintf(buf2, "Fonts directory comparison: %s", unit1->fonts_path); + else + sprintf(buf2, "Fonts directory comparison: "LDIFF(%s)"/"RDIFF(%s), + unit1->fonts_path, unit2->fonts_path); + } + return strdup(buf2); + } + case EX_SCENARIO: { str = "Scenario"; break; } + case EX_IMAGE: { str = "Images"; break; } + case EX_OBJ_INFO: { str = "Objects"; break; } + default: { str = "Unknown"; break; } + } + sprintf(buf, "%s%s", str, compare ? " comparison" : ""); + if (dt == EX_FONTS_DIR) eina_stringshare_del(str); + return strdup(buf); +} + +static char * +_scn_text_get(void *data, Evas_Object *gl, const char *part EINA_UNUSED) +{ + Eina_Strbuf *buf = eina_strbuf_new(); + char *ret = NULL; + Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare"); + if (compare) + { + _Compare_Item_Data *vv = data; + Exactness_Action *a1 = vv->p1; + Exactness_Action *a2 = vv->p2; + + if (!a1 ^ !a2) return strdup("XXXXX"); + + if (a1->delay_ms != a2->delay_ms) eina_strbuf_append_printf(buf, "[+"LDIFF(%.3f)"/+"RDIFF(%.3f)"]: ", a1->delay_ms/1000.0, a2->delay_ms/1000.0); + else eina_strbuf_append_printf(buf, "+%.3f: ", a1->delay_ms / 1000.0); + + if (a1->type != a2->type) + eina_strbuf_append_printf(buf, "["LDIFF(%s)"/"RDIFF(%s)"] - XXXXXX", _action_name_get(a1), _action_name_get(a2)); + else + { + char params1[1024]; + char params2[2024]; + _action_specific_info_get(a1, params1); + _action_specific_info_get(a2, params2); + + eina_strbuf_append_printf(buf, "%s", _action_name_get(a1)); + if (*params1 || *params2) + { + if (strcmp(params1, params2)) + eina_strbuf_append_printf(buf, " - ["LDIFF(%s)"/"RDIFF(%s)"]", params1, params2); + else + eina_strbuf_append_printf(buf, " - %s", params1); + } + } + } + else + { + Exactness_Action *act = data; + char specific_output[1024]; + if (act) + { + eina_strbuf_append_printf(buf, "+%.3f: ", act->delay_ms / 1000.0); + eina_strbuf_append_printf(buf, "%s", _action_name_get(act)); + _action_specific_info_get(act, specific_output); + if (*specific_output) eina_strbuf_append_printf(buf, " - %s", specific_output); + } + else + eina_strbuf_append(buf, "XXXXX"); + } + + ret = eina_strbuf_string_steal(buf); + eina_strbuf_free(buf); + return ret; +} + +static int +_unit_shot_no_get(Exactness_Unit *unit, Exactness_Action *act_ref) +{ + Eina_List *itr; + Exactness_Action *act; + int ret = 0; + if (!unit) return -1; + EINA_LIST_FOREACH(unit->actions, itr, act) + { + if (act->type == EXACTNESS_ACTION_TAKE_SHOT) + { + if (act == act_ref) return ret; + ret++; + } + } + return -1; +} + +static void +_goto_shot(void *data EINA_UNUSED, Evas_Object *bt, void *event_info EINA_UNUSED) +{ + Eo *gl = efl_key_data_get(bt, "gl"); + Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare"); + if (compare) + { + _Compare_Item_Data *vv; + Eina_List *itr; + Eo *gl1 = eina_list_nth(_gls, 0); + Eo *gl2 = eina_list_nth(_gls, 1); + Exactness_Unit *unit1 = efl_key_data_get(gl1, "unit"); + Exactness_Unit *unit2 = efl_key_data_get(gl2, "unit"); + int shot1_no = (intptr_t)efl_key_data_get(bt, "shot1_no"); + int shot2_no = (intptr_t)efl_key_data_get(bt, "shot2_no"); + Exactness_Image *ex_img1 = shot1_no != -1 ? eina_list_nth(unit1->imgs, shot1_no) : NULL; + Exactness_Image *ex_img2 = shot2_no != -1 ? eina_list_nth(unit2->imgs, shot2_no) : NULL; + EINA_LIST_FOREACH(_comp_vvs, itr, vv) + { + if (vv->p1 == ex_img1 && vv->p2 == ex_img2) + { + _Item_Info *ii = eina_hash_find(_item_infos_hash, &vv); + if (ii && ii->gl_item) + elm_genlist_item_show(ii->gl_item, ELM_GENLIST_ITEM_SCROLLTO_MIDDLE); + } + } + } + else + { + Exactness_Unit *unit = efl_key_data_get(gl, "unit"); + int shot_no = (intptr_t)efl_key_data_get(bt, "shot_no"); + Exactness_Image *ex_img = shot_no != -1 ? eina_list_nth(unit->imgs, shot_no) : NULL; + _Item_Info *ii = eina_hash_find(_item_infos_hash, &ex_img); + if (ii && ii->gl_item) + elm_genlist_item_show(ii->gl_item, ELM_GENLIST_ITEM_SCROLLTO_MIDDLE); + } +} + +static Evas_Object * +_scn_content_get(void *data, Evas_Object *gl, const char *part) +{ + Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare"); + if (compare) + { + if (!strcmp(part, "elm.swallow.end")) + { + _Compare_Item_Data *vv = data; + Exactness_Action *v1 = vv->p1; + Exactness_Action *v2 = vv->p2; + if (v1 && v2 && v1->type == EXACTNESS_ACTION_TAKE_SHOT && + v2->type == EXACTNESS_ACTION_TAKE_SHOT) + { + Eo *gl1 = eina_list_nth(_gls, 0); + Eo *gl2 = eina_list_nth(_gls, 1); + Exactness_Unit *unit1 = efl_key_data_get(gl1, "unit"); + Exactness_Unit *unit2 = efl_key_data_get(gl2, "unit"); + int shot1_no = _unit_shot_no_get(unit1, v1); + int shot2_no = _unit_shot_no_get(unit2, v2); + Exactness_Image *ex_img1 = shot1_no != -1 ? eina_list_nth(unit1->imgs, shot1_no) : NULL; + Exactness_Image *ex_img2 = shot2_no != -1 ? eina_list_nth(unit2->imgs, shot2_no) : NULL; + Exactness_Image *ex_imgO = NULL; + exactness_image_compare(ex_img1, ex_img2, &ex_imgO); + + if (ex_imgO) + { + Eo *bt, *ic, *evas_img; + + bt = elm_button_add(gl); + evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(bt); + efl_key_data_set(bt, "gl", gl); + efl_key_data_set(bt, "shot1_no", (void *)(intptr_t)shot1_no); + efl_key_data_set(bt, "shot2_no", (void *)(intptr_t)shot2_no); + evas_object_smart_callback_add(bt, "clicked", _goto_shot, NULL); + + ic = elm_icon_add(bt); + evas_img = elm_image_object_get(ic); + evas_object_image_size_set(evas_img, ex_imgO->w, ex_imgO->h); + evas_object_image_data_set(evas_img, ex_imgO->pixels); + evas_object_show(ic); + elm_object_part_content_set(bt, "icon", ic); + return bt; + } + } + } + } + else + { + if (!strcmp(part, "elm.swallow.end")) + { + Exactness_Action *v = data; + Exactness_Unit *unit = efl_key_data_get(gl, "unit"); + int shot_no = _unit_shot_no_get(unit, v); + Exactness_Image *ex_img = shot_no != -1 ? eina_list_nth(unit->imgs, shot_no) : NULL; + + if (ex_img) + { + Eo *bt, *ic, *evas_img; + + bt = elm_button_add(gl); + evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(bt); + efl_key_data_set(bt, "gl", gl); + efl_key_data_set(bt, "shot_no", (void *)(intptr_t)shot_no); + evas_object_smart_callback_add(bt, "clicked", _goto_shot, NULL); + + ic = elm_icon_add(bt); + evas_img = elm_image_object_get(ic); + evas_object_image_size_set(evas_img, ex_img->w, ex_img->h); + evas_object_image_data_set(evas_img, ex_img->pixels); + evas_object_show(ic); + elm_object_part_content_set(bt, "icon", ic); + + return bt; + } + } + } + return NULL; +} + +static Evas_Object * +_img_content_get(void *data, Evas_Object *gl, const char *part) +{ + if (strcmp(part, "elm.swallow.content")) return NULL; + Eo *img = elm_image_add(gl); + Eo *evas_img = elm_image_object_get(img); + Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare"); + if (compare) + { + _Compare_Item_Data *vv = data; + Exactness_Image *ex_img1 = vv->p1; + Exactness_Image *ex_img2 = vv->p2; + Exactness_Image *ex_imgO = NULL; + exactness_image_compare(ex_img1, ex_img2, &ex_imgO); + + evas_object_image_size_set(evas_img, ex_imgO->w, ex_imgO->h); + evas_object_image_data_set(evas_img, ex_imgO->pixels); + evas_object_size_hint_min_set(img, ELM_SCALE_SIZE(300), ELM_SCALE_SIZE(300)); + } + else + { + if (!data) + { + efl_del(img); + return NULL; + } + Exactness_Image *ex_img = data; + evas_object_image_size_set(evas_img, ex_img->w, ex_img->h); + evas_object_image_data_set(evas_img, ex_img->pixels); + evas_object_size_hint_min_set(img, ELM_SCALE_SIZE(300), ELM_SCALE_SIZE(300)); + } + return img; +} + +static char * +_objs_text_get(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED) +{ + return strdup("Shot"); +} + +static char * +_obj_text_get(void *data, Evas_Object *gl, const char *part EINA_UNUSED) +{ + Eina_Strbuf *buf = eina_strbuf_new(); + char *ret = NULL; + Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare"); + if (compare) + { + _Compare_Item_Data *vv = data; + Exactness_Object *e_obj1 = vv->p1; + Exactness_Object *e_obj2 = vv->p2; + if ((!e_obj1 ^ !e_obj2) || strcmp(e_obj1->kl_name, e_obj2->kl_name)) + eina_strbuf_append_printf(buf, "("LDIFF(%s)"/"RDIFF(%s)")", + e_obj1 ? e_obj1->kl_name : "XXXXX", + e_obj2 ? e_obj2->kl_name : "XXXXX"); + else + eina_strbuf_append_printf(buf, "%s", e_obj1->kl_name); + + eina_strbuf_append(buf, " x = "); + if ((!e_obj1 ^ !e_obj2) || e_obj1->x != e_obj2->x) + eina_strbuf_append_printf(buf, LDIFF(%d)"/"RDIFF(%d), + e_obj1 ? e_obj1->x : -1, + e_obj2 ? e_obj2->x : -1); + else + eina_strbuf_append_printf(buf, "%d", e_obj1->x); + + eina_strbuf_append(buf, " y = "); + if ((!e_obj1 ^ !e_obj2) || e_obj1->y != e_obj2->y) + eina_strbuf_append_printf(buf, LDIFF(%d)"/"RDIFF(%d), + e_obj1 ? e_obj1->y : -1, + e_obj2 ? e_obj2->y : -1); + else + eina_strbuf_append_printf(buf, "%d", e_obj1->y); + + eina_strbuf_append(buf, " w = "); + if ((!e_obj1 ^ !e_obj2) || e_obj1->w != e_obj2->w) + eina_strbuf_append_printf(buf, LDIFF(%d)"/"RDIFF(%d), + e_obj1 ? e_obj1->w : -1, + e_obj2 ? e_obj2->w : -1); + else + eina_strbuf_append_printf(buf, "%d", e_obj1->w); + + eina_strbuf_append(buf, " h = "); + if ((!e_obj1 ^ !e_obj2) || e_obj1->h != e_obj2->h) + eina_strbuf_append_printf(buf, LDIFF(%d)"/"RDIFF(%d), + e_obj1 ? e_obj1->h : -1, + e_obj2 ? e_obj2->h : -1); + else + eina_strbuf_append_printf(buf, "%d", e_obj1->h); + + if (e_obj1 && e_obj2 && _are_objs_different(e_obj1, e_obj2, EINA_FALSE)) + eina_strbuf_append(buf, " - DIFF INSIDE"); + } + else + { + Exactness_Object *e_obj = data; + eina_strbuf_append_printf(buf, + "%s: x = %d y = %d w = %d h = %d", + e_obj->kl_name, + e_obj->x, e_obj->y, e_obj->w, e_obj->h); + } + + ret = eina_strbuf_string_steal(buf); + eina_strbuf_free(buf); + return ret; +} + +static void +_itc_init() +{ + if (!_grp_itc) + { + _grp_itc = elm_genlist_item_class_new(); + _grp_itc->item_style = "group_index"; + _grp_itc->func.text_get = _grp_text_get; + } + + if (!_scn_itc) + { + _scn_itc = elm_genlist_item_class_new(); + _scn_itc->item_style = "default_style"; + _scn_itc->func.text_get = _scn_text_get; + _scn_itc->func.content_get = _scn_content_get; + } + + if (!_img_itc) + { + _img_itc = elm_genlist_item_class_new(); + _img_itc->item_style = "full"; + _img_itc->func.content_get = _img_content_get; + } + + if (!_objs_itc) + { + _objs_itc = elm_genlist_item_class_new(); + _objs_itc->item_style = "default_style"; + _objs_itc->func.text_get = _objs_text_get; + } + + if (!_obj_itc) + { + _obj_itc = elm_genlist_item_class_new(); + _obj_itc->item_style = "default_style"; + _obj_itc->func.text_get = _obj_text_get; + } +} + +static void +_comp_gl_dragged_cb(Evas_Object *obj, void *data EINA_UNUSED) +{ + int x = 0, y = 0; + Eo *gl; + Eina_List *itr; + elm_interface_scrollable_content_pos_get(obj, &x, &y); + EINA_LIST_FOREACH(_gls, itr, gl) + { + if (gl != obj) + elm_interface_scrollable_content_pos_set(gl, x, y, EINA_FALSE); + } +} + +static void +_obj_item_realize(Exactness_Object *ex_obj) +{ + _Item_Info *ii = eina_hash_find(_item_infos_hash, &ex_obj); + if (!ii) return; + if (ii->gl_item) return; + _obj_item_realize(ii->ex_parent); + _Item_Info *iip = eina_hash_find(_item_infos_hash, &(ii->ex_parent)); + if (iip->gl_item) elm_genlist_item_expanded_set(iip->gl_item, EINA_TRUE); +} + +static void +_gl_expand_request_cb(void *data EINA_UNUSED, Evas_Object *gl, void *event_info) +{ + Elm_Object_Item *glit = event_info; + Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare"); + if (compare) + { + const Elm_Genlist_Item_Class *itc = elm_genlist_item_item_class_get(glit); + if (itc == _objs_itc) + { + _Compare_Item_Data *vv = elm_object_item_data_get(glit); + _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1)); + if (ii) elm_genlist_item_expanded_set(ii->gl_item, EINA_TRUE); + ii = eina_hash_find(_item_infos_hash, &(vv->p2)); + if (ii) elm_genlist_item_expanded_set(ii->gl_item, EINA_TRUE); + } + else if (itc == _obj_itc) + { + _Compare_Item_Data *vv = elm_object_item_data_get(glit); + _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1)); + if (!ii || !ii->gl_item) _obj_item_realize(vv->p1); + if (!ii) ii = eina_hash_find(_item_infos_hash, &(vv->p1)); + if (ii && ii->gl_item) elm_genlist_item_expanded_set(ii->gl_item, EINA_TRUE); + + ii = eina_hash_find(_item_infos_hash, &(vv->p2)); + if (!ii || !ii->gl_item) _obj_item_realize(vv->p2); + if (!ii) ii = eina_hash_find(_item_infos_hash, &(vv->p2)); + if (ii && ii->gl_item) elm_genlist_item_expanded_set(ii->gl_item, EINA_TRUE); + } + } + elm_genlist_item_expanded_set(glit, EINA_TRUE); +} + +static void +_gl_contract_request_cb(void *data EINA_UNUSED, Evas_Object *gl EINA_UNUSED, void *event_info) +{ + Elm_Object_Item *glit = event_info; + Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare"); + if (compare) + { + const Elm_Genlist_Item_Class *itc = elm_genlist_item_item_class_get(glit); + if (itc == _objs_itc) + { + _Compare_Item_Data *vv = elm_object_item_data_get(glit); + _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1)); + if (ii) elm_genlist_item_expanded_set(ii->gl_item, EINA_FALSE); + ii = eina_hash_find(_item_infos_hash, &(vv->p2)); + if (ii) elm_genlist_item_expanded_set(ii->gl_item, EINA_FALSE); + } + else if (itc == _obj_itc) + { + _Compare_Item_Data *vv = elm_object_item_data_get(glit); + _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1)); + if (ii && ii->gl_item) elm_genlist_item_expanded_set(ii->gl_item, EINA_FALSE); + + ii = eina_hash_find(_item_infos_hash, &(vv->p2)); + if (ii && ii->gl_item) elm_genlist_item_expanded_set(ii->gl_item, EINA_FALSE); + } + } + elm_genlist_item_expanded_set(glit, EINA_FALSE); +} + +static void +_gl_expanded_cb(void *_data EINA_UNUSED, Evas_Object *gl EINA_UNUSED, void *event_info) +{ + Elm_Object_Item *glit = event_info; + const Elm_Genlist_Item_Class *itc = elm_genlist_item_item_class_get(glit); + Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare"); + if (itc == _objs_itc) + { + if (compare) + { + _Compare_Item_Data *vv = elm_object_item_data_get(glit); + Exactness_Objects *e_objs1 = vv->p1; + Exactness_Objects *e_objs2 = vv->p2; + Eina_List *itr1 = e_objs1->main_objs, *itr2 = e_objs2->main_objs; + + while (itr1 || itr2) + { + Exactness_Object *e_obj1 = eina_list_data_get(itr1); + Exactness_Object *e_obj2 = eina_list_data_get(itr2); + vv = calloc(1, sizeof(*vv)); + vv->p1 = e_obj1; + vv->p2 = e_obj2; + vv->dt = EX_OBJ_INFO; + elm_genlist_item_append(gl, _obj_itc, vv, glit, + e_obj1->children || e_obj2->children ? ELM_GENLIST_ITEM_TREE : ELM_GENLIST_ITEM_NONE, + NULL, NULL); + itr1 = eina_list_next(itr1); + itr2 = eina_list_next(itr2); + } + } + else + { + Exactness_Objects *e_objs = elm_object_item_data_get(glit); + Eina_List *itr; + Exactness_Object *e_obj; + EINA_LIST_FOREACH(e_objs->main_objs, itr, e_obj) + { + _Item_Info *ii = eina_hash_find(_item_infos_hash, &e_obj); + if (!ii) + { + ii = calloc(1, sizeof(*ii)); + eina_hash_set(_item_infos_hash, &e_obj, ii); + } + ii->ex_parent = e_objs; + ii->gl_item = elm_genlist_item_append(gl, _obj_itc, e_obj, glit, + e_obj->children ? ELM_GENLIST_ITEM_TREE : ELM_GENLIST_ITEM_NONE, + NULL, NULL); + efl_wref_add(ii->gl_item, &(ii->gl_item)); + } + } + } + else if (itc == _obj_itc) + { + if (compare) + { + _Compare_Item_Data *vv = elm_object_item_data_get(glit); + Exactness_Object *e_obj1 = vv->p1; + Exactness_Object *e_obj2 = vv->p2; + Eina_List *itr1 = e_obj1->children, *itr2 = e_obj2->children; + + while (itr1 || itr2) + { + e_obj1 = eina_list_data_get(itr1); + e_obj2 = eina_list_data_get(itr2); + vv = calloc(1, sizeof(*vv)); + vv->p1 = e_obj1; + vv->p2 = e_obj2; + vv->dt = EX_OBJ_INFO; + elm_genlist_item_append(gl, _obj_itc, vv, glit, + (e_obj1 && e_obj1->children) || (e_obj2 && e_obj2->children) ? + ELM_GENLIST_ITEM_TREE : ELM_GENLIST_ITEM_NONE, + NULL, NULL); + itr1 = eina_list_next(itr1); + itr2 = eina_list_next(itr2); + } + } + else + { + Exactness_Object *e_obj = elm_object_item_data_get(glit), *e_obj2; + Eina_List *itr; + + EINA_LIST_FOREACH(e_obj->children, itr, e_obj2) + { + _Item_Info *ii = eina_hash_find(_item_infos_hash, &e_obj2); + if (!ii) + { + ii = calloc(1, sizeof(*ii)); + eina_hash_set(_item_infos_hash, &e_obj2, ii); + } + ii->ex_parent = e_obj; + ii->gl_item = elm_genlist_item_append(gl, _obj_itc, e_obj2, glit, + e_obj2->children ? ELM_GENLIST_ITEM_TREE : ELM_GENLIST_ITEM_NONE, + NULL, NULL); + efl_wref_add(ii->gl_item, &(ii->gl_item)); + } + } + } +} + +static void +_gl_contracted_cb(void *data EINA_UNUSED, Evas_Object *gl EINA_UNUSED, void *event_info) +{ + Elm_Object_Item *glit = event_info; + elm_genlist_item_subitems_clear(glit); +} + +static void +_comp_gl_selected_cb(void *data EINA_UNUSED, Evas_Object *gl EINA_UNUSED, void *event_info) +{ + _comp_selected_item = event_info; + _Compare_Item_Data *vv = elm_object_item_data_get(_comp_selected_item); + if (vv->p1) + { + _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1)); + if (!ii || !ii->gl_item) _obj_item_realize(vv->p1); + elm_genlist_item_selected_set(ii->gl_item, EINA_TRUE); + } + + if (vv->p2) + { + _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p2)); + if (!ii || !ii->gl_item) _obj_item_realize(vv->p2); + elm_genlist_item_selected_set(ii->gl_item, EINA_TRUE); + } +} + +static void +_scn_item_remove(void *data, Evas_Object *menu EINA_UNUSED, void *item EINA_UNUSED) +{ + Eo *glit = data; + Exactness_Unit *unit = efl_key_data_get(efl_parent_get(glit), "unit"); + Exactness_Action *act = elm_object_item_data_get(glit); + unit->actions = eina_list_remove(unit->actions, act); + if (!eina_list_data_find(_modified_units, unit)) + _modified_units = eina_list_append(_modified_units, unit); + efl_del(glit); +} + +static void +_gl_clicked_right_cb(void *data, Evas_Object *gl, void *event_info) +{ + int x = 0, y = 0; + Eo *win = data, *menu; + Elm_Object_Item *glit = event_info; + + if (elm_genlist_item_item_class_get(glit) == _scn_itc) + { + elm_genlist_item_selected_set(glit, EINA_TRUE); + evas_pointer_canvas_xy_get(evas_object_evas_get(gl), &x, &y); + + menu = elm_menu_add(win); + elm_menu_move(menu, x, y); + elm_menu_item_add(menu, NULL, NULL, "Remove", _scn_item_remove, glit); + efl_gfx_entity_visible_set(menu, EINA_TRUE); + } +} + +static void +_gl_img_show(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + static Eo *_img_win = NULL; + Exactness_Image *ex_img = data; + if (_img_win) efl_del(_img_win); + _img_win = efl_add(EFL_UI_WIN_CLASS, elm_win_get(obj), + efl_ui_win_type_set(efl_added, EFL_UI_WIN_TYPE_DIALOG_BASIC), + efl_ui_win_autodel_set(efl_added, EINA_TRUE)); + efl_wref_add(_img_win, &_img_win); + + Evas_Object *image = elm_image_add(_img_win); + Eo *evas_img = elm_image_object_get(image); + evas_object_image_size_set(evas_img, ex_img->w, ex_img->h); + evas_object_image_data_set(evas_img, ex_img->pixels); + efl_content_set(_img_win, image); + + efl_gfx_entity_size_set(_img_win, EINA_SIZE2D(550, 500)); +} + +static void +_gui_unit_display(Exactness_Unit *unit1, Exactness_Unit *unit2) +{ + Eina_List *itr1, *itr2; + Eo *gl1, *gl2 = NULL, *glc = NULL; + + gl1 = elm_genlist_add(_main_box); + elm_genlist_homogeneous_set(gl1, EINA_TRUE); + evas_object_size_hint_weight_set(gl1, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(gl1, EVAS_HINT_FILL, EVAS_HINT_FILL); + efl_gfx_entity_visible_set(gl1, EINA_TRUE); + _gls = eina_list_append(_gls, gl1); + elm_box_pack_end(_main_box, gl1); + + efl_key_data_set(gl1, "unit", unit1); + evas_object_smart_callback_add(gl1, "expand,request", _gl_expand_request_cb, NULL); + evas_object_smart_callback_add(gl1, "contract,request", _gl_contract_request_cb, NULL); + evas_object_smart_callback_add(gl1, "expanded", _gl_expanded_cb, NULL); + evas_object_smart_callback_add(gl1, "contracted", _gl_contracted_cb, NULL); + if (!unit2) + evas_object_smart_callback_add(gl1, "clicked,right", _gl_clicked_right_cb, elm_win_get(_main_box)); + + if (unit2) + { + glc = elm_genlist_add(_main_box); + elm_genlist_homogeneous_set(glc, EINA_TRUE); + evas_object_size_hint_weight_set(glc, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(glc, EVAS_HINT_FILL, EVAS_HINT_FILL); + efl_gfx_entity_visible_set(glc, EINA_TRUE); + elm_box_pack_end(_main_box, glc); + + evas_object_smart_callback_add(glc, "expand,request", _gl_expand_request_cb, NULL); + evas_object_smart_callback_add(glc, "contract,request", _gl_contract_request_cb, NULL); + evas_object_smart_callback_add(glc, "expanded", _gl_expanded_cb, NULL); + evas_object_smart_callback_add(glc, "contracted", _gl_contracted_cb, NULL); + + efl_key_data_set(glc, "_exactness_gl_compare", glc); + elm_interface_scrollable_scroll_down_cb_set(glc, _comp_gl_dragged_cb); + elm_interface_scrollable_scroll_up_cb_set(glc, _comp_gl_dragged_cb); + evas_object_smart_callback_add(glc, "selected", _comp_gl_selected_cb, NULL); + + gl2 = elm_genlist_add(_main_box); + elm_genlist_homogeneous_set(gl2, EINA_TRUE); + evas_object_size_hint_weight_set(gl2, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(gl2, EVAS_HINT_FILL, EVAS_HINT_FILL); + efl_gfx_entity_visible_set(gl2, EINA_TRUE); + _gls = eina_list_append(_gls, gl2); + elm_box_pack_end(_main_box, gl2); + + efl_key_data_set(gl2, "unit", unit2); + evas_object_smart_callback_add(gl2, "expand,request", _gl_expand_request_cb, NULL); + evas_object_smart_callback_add(gl2, "contract,request", _gl_contract_request_cb, NULL); + evas_object_smart_callback_add(gl2, "expanded", _gl_expanded_cb, NULL); + evas_object_smart_callback_add(gl2, "contracted", _gl_contracted_cb, NULL); + } + _itc_init(); + + if (unit1->fonts_path || (unit2 && unit2->fonts_path)) + { + if (!_show_only_diffs || !unit1 || !unit2 || + !unit1->fonts_path || !unit2->fonts_path || + strcmp(unit1->fonts_path, unit2->fonts_path)) + { + elm_genlist_item_append(gl1, _grp_itc, (void *)EX_FONTS_DIR, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + elm_genlist_item_append(gl2, _grp_itc, (void *)EX_FONTS_DIR, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + elm_genlist_item_append(glc, _grp_itc, (void *)EX_FONTS_DIR, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + } + } + itr1 = unit1 ? unit1->actions : NULL; + itr2 = unit2 ? unit2->actions : NULL; + + if (itr1 || itr2) + { + elm_genlist_item_append(gl1, _grp_itc, (void *)EX_SCENARIO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + elm_genlist_item_append(gl2, _grp_itc, (void *)EX_SCENARIO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + elm_genlist_item_append(glc, _grp_itc, (void *)EX_SCENARIO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + } + while (itr1 || itr2) + { + Exactness_Action *v1 = itr1 ? eina_list_data_get(itr1) : NULL; + Exactness_Action *v2 = itr2 ? eina_list_data_get(itr2) : NULL; + if (!_show_only_diffs || _are_scenario_entries_different(v1, v2)) + { + _Item_Info *ii = calloc(1, sizeof(*ii)); + eina_hash_set(_item_infos_hash, &v1, ii); + ii->gl_item = elm_genlist_item_append(gl1, _scn_itc, v1, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + if (unit2) + { + _Compare_Item_Data *vv = calloc(1, sizeof(*vv)); + vv->p1 = v1; + vv->p2 = v2; + vv->dt = EX_SCENARIO; + ii = calloc(1, sizeof(*ii)); + eina_hash_set(_item_infos_hash, &v2, ii); + ii->gl_item = elm_genlist_item_append(gl2, _scn_itc, v2, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + elm_genlist_item_append(glc, _scn_itc, vv, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + } + } + if (itr1) itr1 = eina_list_next(itr1); + if (itr2) itr2 = eina_list_next(itr2); + } + + itr1 = unit1 ? unit1->imgs : NULL; + itr2 = unit2 ? unit2->imgs : NULL; + + if (itr1 || itr2) + { + elm_genlist_item_append(gl1, _grp_itc, (void *)EX_IMAGE, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + elm_genlist_item_append(gl2, _grp_itc, (void *)EX_IMAGE, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + elm_genlist_item_append(glc, _grp_itc, (void *)EX_IMAGE, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + } + while (itr1 || itr2) + { + Exactness_Image *img1 = itr1 ? eina_list_data_get(itr1) : NULL; + Exactness_Image *img2 = itr2 ? eina_list_data_get(itr2) : NULL; + if (!_show_only_diffs || _are_images_different(img1, img2)) + { + _Item_Info *ii = calloc(1, sizeof(*ii)); + eina_hash_set(_item_infos_hash, &img1, ii); + ii->gl_item = elm_genlist_item_append(gl1, _img_itc, img1, NULL, ELM_GENLIST_ITEM_NONE, _gl_img_show, img1); + if (unit2) + { + _Compare_Item_Data *vv = calloc(1, sizeof(*vv)); + vv->p1 = img1; + vv->p2 = img2; + vv->dt = EX_IMAGE; + ii = calloc(1, sizeof(*ii)); + eina_hash_set(_item_infos_hash, &img2, ii); + ii->gl_item = elm_genlist_item_append(gl2, _img_itc, img2, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + /* This item info is needed to go to images from scenario shot entry */ + ii = calloc(1, sizeof(*ii)); + eina_hash_set(_item_infos_hash, &vv, ii); + ii->gl_item = elm_genlist_item_append(glc, _img_itc, vv, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + _comp_vvs = eina_list_append(_comp_vvs, vv); + } + } + if (itr1) itr1 = eina_list_next(itr1); + if (itr2) itr2 = eina_list_next(itr2); + } + + itr1 = unit1 ? unit1->objs : NULL; + itr2 = unit2 ? unit2->objs : NULL; + + if (itr1 || itr2) + { + elm_genlist_item_append(gl1, _grp_itc, (void *)EX_OBJ_INFO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + elm_genlist_item_append(gl2, _grp_itc, (void *)EX_OBJ_INFO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + elm_genlist_item_append(glc, _grp_itc, (void *)EX_OBJ_INFO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + } + while (itr1 || itr2) + { + Exactness_Objects *objs1 = itr1 ? eina_list_data_get(itr1) : NULL; + Exactness_Objects *objs2 = itr2 ? eina_list_data_get(itr2) : NULL; + if (!_show_only_diffs || _are_objs_trees_different(objs1, objs2)) + { + _Item_Info *ii = calloc(1, sizeof(*ii)); + eina_hash_set(_item_infos_hash, &objs1, ii); + ii->gl_item = elm_genlist_item_append(gl1, _objs_itc, objs1, NULL, + ELM_GENLIST_ITEM_TREE, NULL, NULL); + efl_wref_add(ii->gl_item, &(ii->gl_item)); + if (unit2) + { + _Compare_Item_Data *vv = calloc(1, sizeof(*vv)); + vv->p1 = objs1; + vv->p2 = objs2; + vv->dt = EX_OBJ_INFO; + ii = calloc(1, sizeof(*ii)); + eina_hash_set(_item_infos_hash, &objs2, ii); + ii->gl_item = elm_genlist_item_append(gl2, _objs_itc, objs2, NULL, + ELM_GENLIST_ITEM_TREE, NULL, NULL); + efl_wref_add(ii->gl_item, &(ii->gl_item)); + elm_genlist_item_append(glc, _objs_itc, vv, NULL, ELM_GENLIST_ITEM_TREE, NULL, NULL); + } + } + if (itr1) itr1 = eina_list_next(itr1); + if (itr2) itr2 = eina_list_next(itr2); + } +} + +static void +_diff_result_print(Exactness_Unit *unit1, Exactness_Unit *unit2) +{ + Eina_List *itr1, *itr2; + + int nb_scenario = 0, nb_diff_scenario = 0; + int nb_image = 0, nb_diff_image = 0; + int nb_objtree= 0, nb_diff_objtree = 0; + + itr1 = unit1 ? unit1->actions : NULL; + itr2 = unit2 ? unit2->actions : NULL; + + while (itr1 || itr2) + { + Exactness_Action *v1 = itr1 ? eina_list_data_get(itr1) : NULL; + Exactness_Action *v2 = itr2 ? eina_list_data_get(itr2) : NULL; + + nb_scenario++; + if (_are_scenario_entries_different(v1, v2)) + nb_diff_scenario++; + + if (itr1) itr1 = eina_list_next(itr1); + if (itr2) itr2 = eina_list_next(itr2); + } + + itr1 = unit1 ? unit1->imgs : NULL; + itr2 = unit2 ? unit2->imgs : NULL; + + while (itr1 || itr2) + { + Exactness_Image *img1 = itr1 ? eina_list_data_get(itr1) : NULL; + Exactness_Image *img2 = itr2 ? eina_list_data_get(itr2) : NULL; + + nb_image++; + if (_are_images_different(img1, img2)) + nb_diff_image++; + + if (itr1) itr1 = eina_list_next(itr1); + if (itr2) itr2 = eina_list_next(itr2); + } + + itr1 = unit1 ? unit1->objs : NULL; + itr2 = unit2 ? unit2->objs : NULL; + + while (itr1 || itr2) + { + Exactness_Objects *objs1 = itr1 ? eina_list_data_get(itr1) : NULL; + Exactness_Objects *objs2 = itr2 ? eina_list_data_get(itr2) : NULL; + + nb_objtree++; + if (_are_objs_trees_different(objs1, objs2)) + nb_diff_objtree++; + + if (itr1) itr1 = eina_list_next(itr1); + if (itr2) itr2 = eina_list_next(itr2); + } + + printf("%s\nscenario (%d/%d)\nimage (%d/%d)\nobjs_tree (%d/%d)\n", + nb_diff_scenario || nb_diff_image || nb_diff_objtree ? + "Failure" : "Success", + nb_scenario - nb_diff_scenario, nb_scenario, + nb_image - nb_diff_image, nb_image, + nb_objtree - nb_diff_objtree, nb_objtree); +} + +static Exactness_Image * +_image_read(const char *filename) +{ + int w, h; + Evas_Load_Error err; + Ecore_Evas *ee = ecore_evas_new(NULL, 0, 0, 100, 100, NULL); + + /* the canvas pointer, de facto */ + Eo *e = ecore_evas_get(ee); + + Eo *img = evas_object_image_add(e); + evas_object_image_file_set(img, filename, NULL); + err = evas_object_image_load_error_get(img); + if (err != EVAS_LOAD_ERROR_NONE) + { + fprintf(stderr, "could not load image '%s'. error string is \"%s\"\n", + filename, evas_load_error_str(err)); + return NULL; + } + + Exactness_Image *ex_img = malloc(sizeof(*ex_img)); + int len; + evas_object_image_size_get(img, &w, &h); + ex_img->w = w; + ex_img->h = h; + len = w * h * 4; + ex_img->pixels = malloc(len); + memcpy(ex_img->pixels, evas_object_image_data_get(img, EINA_FALSE), len); + + ecore_evas_free(ee); + return ex_img; +} + +static const Ecore_Getopt optdesc = { + "exactness_inspect", + "%prog [options] [<rec file> | <file1 file2>]", + NULL, + "(C) 2016 Enlightenment", + "BSD", + "Inspector for Exactness", + 0, + { + ECORE_GETOPT_STORE_USHORT('d', "delay", "Delay the given recording by a given time (in milliseconds)."), + ECORE_GETOPT_STORE_TRUE('c', "clean", "Clean the given recording from wrong actions."), + ECORE_GETOPT_STORE_TRUE('l', "list", "List the actions of the given recording."), + ECORE_GETOPT_STORE_TRUE('C', "compare", "Compare given files (images files or objects eet files)."), + ECORE_GETOPT_STORE_TRUE(0, "show-only-diffs", "Show only differences during comparison."), + ECORE_GETOPT_STORE_TRUE(0, "stabilize", "Stabilize after the given shot number in --shot."), + ECORE_GETOPT_STORE_TRUE(0, "pack", "Pack the given input files (scenario and images) into the given output."), + ECORE_GETOPT_STORE_STR('o', "output", "Output."), + ECORE_GETOPT_STORE_USHORT('s', "shot", "Select a specific shot (1 = 1st shot...)."), + + ECORE_GETOPT_LICENSE('L', "license"), + ECORE_GETOPT_COPYRIGHT('C', "copyright"), + ECORE_GETOPT_VERSION('V', "version"), + ECORE_GETOPT_HELP('h', "help"), + ECORE_GETOPT_SENTINEL + } +}; + +int +main(int argc, char *argv[]) +{ + Eina_List *units_filenames = NULL; + const char *ext = NULL; + char *output = NULL; + Exactness_Unit *unit = NULL; + int ret = 1, args = 0; + unsigned short delay = 0, shot = 0; + Eina_Bool write_file = EINA_FALSE; + Eina_Bool want_quit, clean = EINA_FALSE, list_get = EINA_FALSE, compare_files = EINA_FALSE; + Eina_Bool stabilize = EINA_FALSE, show_only_diffs = EINA_FALSE, gui_needed = EINA_TRUE; + Eina_Bool pack = EINA_FALSE; + + Ecore_Getopt_Value values[] = { + ECORE_GETOPT_VALUE_USHORT(delay), + ECORE_GETOPT_VALUE_BOOL(clean), + ECORE_GETOPT_VALUE_BOOL(list_get), + ECORE_GETOPT_VALUE_BOOL(compare_files), + ECORE_GETOPT_VALUE_BOOL(show_only_diffs), + ECORE_GETOPT_VALUE_BOOL(stabilize), + ECORE_GETOPT_VALUE_BOOL(pack), + ECORE_GETOPT_VALUE_STR(output), + ECORE_GETOPT_VALUE_USHORT(shot), + + ECORE_GETOPT_VALUE_BOOL(want_quit), + ECORE_GETOPT_VALUE_BOOL(want_quit), + ECORE_GETOPT_VALUE_BOOL(want_quit), + ECORE_GETOPT_VALUE_BOOL(want_quit), + ECORE_GETOPT_VALUE_NONE + }; + + ecore_evas_init(); + ecore_init(); + eet_init(); + elm_init(0, NULL); + want_quit = EINA_FALSE; + + args = ecore_getopt_parse(&optdesc, values, argc, argv); + if (args < 0) + { + fprintf(stderr, "Failed parsing arguments.\n"); + goto end; + } + if (want_quit) + { + goto end; + } + if ((clean || delay || shot || list_get || stabilize || pack) && args == argc) + { + fprintf(stderr, "Expected scenario (.rec/.exu) as the last argument.\n"); + ecore_getopt_help(stderr, &optdesc); + goto end; + } + if (shot && (!delay && !stabilize)) + { + fprintf(stderr, "shot option can only be used with delay or stabilize option.\n"); + goto end; + } + if (delay && !shot) + { + fprintf(stderr, "delay option can only be used with shot option.\n"); + goto end; + } + if (stabilize && !shot) + { + fprintf(stderr, "stabilize option can only be used with shot option.\n"); + goto end; + } + if (compare_files && argc - args < 2) + { + fprintf(stderr, "Expected at least two files to compare as last arguments.\n"); + ecore_getopt_help(stderr, &optdesc); + goto end; + } + if (show_only_diffs && !compare_files) + { + fprintf(stderr, "--show-only-diffs is available with --compare only\n"); + goto end; + } + if (show_only_diffs && output) + { + fprintf(stderr, "--show-only-diffs works in GUI only\n"); + goto end; + } + _show_only_diffs = show_only_diffs; + + if (clean || delay || list_get || stabilize || pack) + { + int arg; + Eina_List *images = NULL; + gui_needed = EINA_FALSE; + for (arg = args; arg < argc; arg++) + { + const char *src_file = argv[arg]; + ext = strrchr(src_file, '.'); + if (!ext) + { + fprintf(stderr, "Extension required\n"); + goto end; + } + if (!strcmp(ext, ".exu")) + { + if (!unit) unit = exactness_unit_file_read(src_file); + else + { + fprintf(stderr, "%s - scenario already provided\n", src_file); + goto end; + } + } + else if (!strcmp(ext, ".rec")) + { + if (!unit) unit = legacy_rec_file_read(src_file); + else + { + fprintf(stderr, "%s - scenario already provided\n", src_file); + goto end; + } + } + else if (!strcmp(ext, ".png")) + { + Exactness_Image *ex_img = _image_read(src_file); + if (!ex_img) + { + fprintf(stderr, "Issue while reading %s\n", src_file); + goto end; + } + images = eina_list_append(images, ex_img); + } + else + { + fprintf(stderr, "Correct extension (.exu/.rec/.png) required\n"); + goto end; + } + } + if (unit) + { + Exactness_Image *ex_img; + EINA_LIST_FREE(images, ex_img) + { + unit->imgs = eina_list_append(unit->imgs, ex_img); + unit->nb_shots++; + } + } + } + else + { + int arg; + if (output) gui_needed = EINA_FALSE; + for (arg = args; arg < argc; arg++) + { + ext = strrchr(argv[arg], '.'); + if (!ext) + { + fprintf(stderr, "Extension required\n"); + goto end; + } + if (!strcmp(ext, ".exu")) + { + Exactness_Unit *ex_unit = exactness_unit_file_read(argv[arg]); + units_filenames = eina_list_append(units_filenames, argv[arg]); + _units = eina_list_append(_units, ex_unit); + } + else if (!strcmp(ext, ".rec")) + { + Exactness_Unit *ex_unit = legacy_rec_file_read(argv[arg]); + if (!ex_unit) + { + fprintf(stderr, "Issue while reading %s\n", argv[arg]); + goto end; + } + _units = eina_list_append(_units, ex_unit); + } + else if (!strcmp(ext, ".png")) + { + Exactness_Unit *ex_unit = calloc(1, sizeof(*ex_unit)); + Exactness_Image *ex_img = _image_read(argv[arg]); + if (!ex_img) + { + fprintf(stderr, "Issue while reading %s\n", argv[arg]); + goto end; + } + ex_unit->imgs = eina_list_append(ex_unit->imgs, ex_img); + ex_unit->nb_shots++; + _units = eina_list_append(_units, ex_unit); + } + } + } + + if (clean) + { + Exactness_Action *act; + Eina_List *itr, *itr2; + EINA_LIST_FOREACH_SAFE(unit->actions, itr, itr2, act) + { + Exactness_Action *prev_act = eina_list_data_get(eina_list_prev(itr)); + if (_is_hook_duplicate(act, prev_act)) + { + prev_act->delay_ms += act->delay_ms; + unit->actions = eina_list_remove_list(unit->actions, itr); + } + } + EINA_LIST_REVERSE_FOREACH_SAFE(unit->actions, itr, itr2, act) + { + if (act->type == EXACTNESS_ACTION_TAKE_SHOT) break; + unit->actions = eina_list_remove(unit->actions, act); + } + write_file = EINA_TRUE; + } + + if (delay || stabilize) + { + Exactness_Action *act; + Eina_List *itr; + unsigned int cur_shot = 0; + EINA_LIST_FOREACH(unit->actions, itr, act) + { + if (act->type == EXACTNESS_ACTION_TAKE_SHOT) + { + cur_shot++; + if (cur_shot == shot) + { + if (delay) act->delay_ms = delay; + if (stabilize) + { + Exactness_Action *s_act = malloc(sizeof(*s_act)); + s_act->type = EXACTNESS_ACTION_STABILIZE; + s_act->delay_ms = act->delay_ms; + s_act->n_evas = act->n_evas; + s_act->data = NULL; + act->delay_ms = 0; /* Shot right after stabilization */ + unit->actions = eina_list_prepend_relative(unit->actions, s_act, act); + } + write_file = EINA_TRUE; + break; + } + } + } + } + + if (pack) write_file = EINA_TRUE; + + if (list_get) + { + Exactness_Action *act; + Eina_List *itr; + if (unit->fonts_path) printf("Fonts dir: %s\n", unit->fonts_path); + EINA_LIST_FOREACH(unit->actions, itr, act) + { + char specific_output[1024]; + printf("+%.3f: %s", act->delay_ms / 1000.0, _action_name_get(act)); + _action_specific_info_get(act, specific_output); + if (*specific_output) printf(" - %s", specific_output); + printf("\n"); + } + } + + if (compare_files && output) + { + const char *out_ext = strrchr(output, '.'); + Exactness_Unit *unit1 = NULL, *unit2 = NULL, *unitO = NULL; + int nb_diffs = 0; + Eina_List *itr1, *itr2; + EINA_LIST_FOREACH(_units, itr1, unit) + { + if (!unit1) unit1 = unit; + else if (!unit2) unit2 = unit; + else + { + fprintf(stderr, "Too much files to compare (only 2).\n"); + goto end; + } + } + + if (!strcmp(out_ext, ".png")) + { + if (unit1->nb_shots != 1 || unit2->nb_shots != 1) + { + fprintf(stderr, "Comparison output can be png only if the number of shots to compare is 1.\n"); + goto end; + } + } + + itr1 = unit1 ? unit1->imgs : NULL; + itr2 = unit2 ? unit2->imgs : NULL; + + while (itr1 || itr2) + { + Exactness_Image *ex_img1 = itr1 ? eina_list_data_get(itr1) : NULL; + Exactness_Image *ex_img2 = itr2 ? eina_list_data_get(itr2) : NULL; + Exactness_Image *ex_imgO = NULL; + Eina_Bool has_diff = exactness_image_compare(ex_img1, ex_img2, &ex_imgO); + if (has_diff || !strcmp(out_ext, ".exu")) + { + if (has_diff) nb_diffs++; + if (!unitO) unitO = calloc(1, sizeof(*unitO)); + unitO->imgs = eina_list_append(unitO->imgs, ex_imgO); + unitO->nb_shots++; + } + itr1 = eina_list_next(itr1); + itr2 = eina_list_next(itr2); + } + if (!strcmp(out_ext, ".png")) + { + Ecore_Evas *ee; + Eo *e, *img; + if (unitO->nb_shots == 1) + { + Exactness_Image *ex_imgO = eina_list_data_get(unitO->imgs); + ee = ecore_evas_new(NULL, 0, 0, 100, 100, NULL); + e = ecore_evas_get(ee); + img = evas_object_image_add(e); + evas_object_image_size_set(img, ex_imgO->w, ex_imgO->h); + evas_object_image_data_set(img, ex_imgO->pixels); + evas_object_image_save(img, output, NULL, NULL); + ecore_evas_free(ee); + goto end; + } + ret = 0; + } + else if (!strcmp(out_ext, ".exu")) + { + _diff_result_print(unit1, unit2); + if (nb_diffs) exactness_unit_file_write(unitO, output); + else ret = 0; + } + else + { + fprintf(stderr, "Correct output extension (.exu/.png) required\n"); + } + goto end; + } + + ret = 0; + if (write_file) + { + if (!output) + { + fprintf(stderr, "An output file is required to write the modifications.\n"); + } + else + { + const char *out_ext = strrchr(output, '.'); + if (!out_ext || strcmp(out_ext, ".exu")) + { + fprintf(stderr, "Only exu extension is supported as output.\n"); + goto end; + } + exactness_unit_file_write(unit, output); + } + goto end; + } + + if (gui_needed) + { + Eina_List *itr; + Exactness_Unit *unit1 = NULL, *unit2 = NULL; + Eina_Bool need_compare = compare_files && eina_list_count(_units) == 2; + _item_infos_hash = eina_hash_pointer_new(NULL); + _gui_win_create(); + EINA_LIST_FOREACH(_units, itr, unit) + { + if (need_compare) + { + if (!unit1) unit1 = unit; + else unit2 = unit; + } + else _gui_unit_display(unit, NULL); + } + if (need_compare) _gui_unit_display(unit1, unit2); + elm_run(); + EINA_LIST_FREE(_modified_units, unit) + { + int i = 0; + EINA_LIST_FOREACH(_units, itr, unit2) + { + if (unit2 == unit) break; + i++; + } + exactness_unit_file_write(unit, eina_list_nth(units_filenames, i)); + } + } + +end: + elm_shutdown(); + eet_shutdown(); + ecore_shutdown(); + ecore_evas_shutdown(); + + return ret; +} |