diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 8fbf2c4..916b291 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -1,10 +1,10 @@ MAINTAINERCLEANFILES = Makefile.in -bin_PROGRAMS = exactness exactness_helper exactness_play exactness_record +bin_PROGRAMS = exactness exactness_inspect exactness_play exactness_record exactness_SOURCES = exactness.c ../lib/tsuite_file_data.c ../lib/tsuite_common.c -exactness_helper_SOURCES = exactness_helper.c ../lib/tsuite_file_data.c ../lib/tsuite_common.c +exactness_inspect_SOURCES = inspect.c ../lib/tsuite_file_data.c ../lib/tsuite_common.c exactness_play_SOURCES = player.c ../lib/tsuite_file_data.c ../lib/tsuite_common.c @@ -12,7 +12,7 @@ exactness_record_SOURCES = recorder.c ../lib/tsuite_file_data.c ../lib/tsuite_co exactness_LDADD = @EFL_LIBS@ -exactness_helper_LDADD = @EFL_LIBS@ +exactness_inspect_LDADD = @EFL_LIBS@ exactness_play_LDADD = @EFL_LIBS@ @@ -24,7 +24,7 @@ exactness_CFLAGS = \ -DPACKAGE_LIBDIR=\"$(libdir)\" \ -DPACKAGE_DATADIR=\"$(datadir)\" -exactness_helper_CFLAGS = @EFL_CFLAGS@ -I$(top_srcdir)/src/lib +exactness_inspect_CFLAGS = @EFL_CFLAGS@ -I$(top_srcdir)/src/lib exactness_play_CFLAGS = @EFL_CFLAGS@ -I$(top_srcdir)/src/lib diff --git a/src/bin/exactness_helper.c b/src/bin/exactness_helper.c deleted file mode 100644 index c3bd134..0000000 --- a/src/bin/exactness_helper.c +++ /dev/null @@ -1,331 +0,0 @@ -#include -#include - -#include "tsuite_file_data.h" - -static const char * -_event_name_get(const Variant_st *v) -{ - switch(tsuite_event_mapping_type_get(v->t.type)) - { - case TSUITE_EVENT_MOUSE_IN: return "Mouse In"; - case TSUITE_EVENT_MOUSE_OUT: return "Mouse Out"; - case TSUITE_EVENT_MOUSE_DOWN: return "Mouse Down"; - case TSUITE_EVENT_MOUSE_UP: return "Mouse Up"; - case TSUITE_EVENT_MOUSE_MOVE: return "Mouse Move"; - case TSUITE_EVENT_MOUSE_WHEEL: return "Mouse Wheel"; - case TSUITE_EVENT_MULTI_DOWN: return "Multi Down"; - case TSUITE_EVENT_MULTI_UP: return "Multi Up"; - case TSUITE_EVENT_MULTI_MOVE: return "Multi Move"; - case TSUITE_EVENT_KEY_DOWN: return "Key Down"; - case TSUITE_EVENT_KEY_UP: return "Key Up"; - case TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE: return "Key Down with Keycode"; - case TSUITE_EVENT_KEY_UP_WITH_KEYCODE: return "Key Up with Keycode"; - case TSUITE_EVENT_TAKE_SHOT: return "Take shot"; - default: return NULL; - } -} - -static int -_event_struct_len_get(Tsuite_Event_Type type) -{ - switch(type) - { - case TSUITE_EVENT_MOUSE_IN: case TSUITE_EVENT_MOUSE_OUT: return sizeof(mouse_in_mouse_out); - case TSUITE_EVENT_MOUSE_DOWN: case TSUITE_EVENT_MOUSE_UP: return sizeof(mouse_down_mouse_up); - case TSUITE_EVENT_MOUSE_MOVE: return sizeof(mouse_move); - case TSUITE_EVENT_MOUSE_WHEEL: return sizeof(mouse_wheel); - case TSUITE_EVENT_MULTI_DOWN: case TSUITE_EVENT_MULTI_UP: return sizeof(multi_move); - case TSUITE_EVENT_MULTI_MOVE: return sizeof(multi_event); - case TSUITE_EVENT_KEY_DOWN: case TSUITE_EVENT_KEY_UP: return sizeof(key_down_key_up); - case TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE: case TSUITE_EVENT_KEY_UP_WITH_KEYCODE: return sizeof(key_down_key_up_with_keycode); - case TSUITE_EVENT_TAKE_SHOT: return sizeof(take_screenshot); - default: return 0; - } -} - -static void -_event_specific_info_get(const Variant_st *v, char output[1024]) -{ - switch(tsuite_event_mapping_type_get(v->t.type)) - { - case TSUITE_EVENT_MOUSE_DOWN: - { - mouse_down_mouse_up *t = v->data; - sprintf(output, "Button %d Flags %d", t->b, t->flags); - break; - } - case TSUITE_EVENT_MOUSE_UP: - { - mouse_down_mouse_up *t = v->data; - sprintf(output, "Button %d Flags %d", t->b, t->flags); - break; - } - case TSUITE_EVENT_MOUSE_MOVE: - { - mouse_move *t = v->data; - sprintf(output, "X %d Y %d", t->x, t->y); - break; - } - case TSUITE_EVENT_MOUSE_WHEEL: - { - mouse_wheel *t = v->data; - sprintf(output, "Direction %d Z %d", t->direction, t->z); - break; - } - case TSUITE_EVENT_MULTI_DOWN: case TSUITE_EVENT_MULTI_UP: - { - multi_event *t = v->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 TSUITE_EVENT_MULTI_MOVE: - { - multi_move *t = v->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 TSUITE_EVENT_KEY_UP: case TSUITE_EVENT_KEY_DOWN: - { - key_down_key_up *t = v->data; - sprintf(output, "Keyname %s Key %s String %s Compose %s", - t->keyname, t->key, t->string, t->compose); - break; - } - case TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE: case TSUITE_EVENT_KEY_UP_WITH_KEYCODE: - { - key_down_key_up_with_keycode *t = v->data; - sprintf(output, "Keyname %s Key %s String %s Compose %s Keycode %d", - t->keyname, t->key, t->string, t->compose, t->keycode); - break; - } - default: - { - output[0] = '\0'; - break; - } - } -} -static const Ecore_Getopt optdesc = { - "exactness_helper", - "%prog [options] [ | ]", - NULL, - "(C) 2016 Enlightenment", - "BSD", - "Helper 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 events."), - ECORE_GETOPT_STORE_TRUE('l', "list", "List the events of the given recording."), - ECORE_GETOPT_STORE_TRUE('C', "compare", "Compare two given files (images files or objects eet files)."), - 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 - } -}; - -static Eina_Bool -_is_hook_duplicate(const Variant_st *cur_v, const Variant_st *prev_v) -{ - if (!prev_v) return EINA_FALSE; - Tsuite_Event_Type cur_type = tsuite_event_mapping_type_get(cur_v->t.type); - Tsuite_Event_Type prev_type = tsuite_event_mapping_type_get(prev_v->t.type); - if (cur_type == prev_type && - !memcmp(cur_v->data, prev_v->data, _event_struct_len_get(cur_type))) return EINA_TRUE; - return EINA_FALSE; -} - -int -main(int argc, char *argv[]) -{ - const char *rec_file = NULL, *comp1 = NULL, *comp2 = NULL; - int ret = 0, 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; - 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_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_init(); - want_quit = EINA_FALSE; - - args = ecore_getopt_parse(&optdesc, values, argc, argv); - if (args < 0) - { - fprintf(stderr, "Failed parsing arguments.\n"); - ret = 1; - goto end; - } - else if (want_quit) - { - ret = 1; - goto end; - } - else if ((clean || delay || shot || list_get) && args == argc) - { - fprintf(stderr, "Expected rec file as the last argument..\n"); - ecore_getopt_help(stderr, &optdesc); - ret = 1; - goto end; - } - else if (shot && !delay) - { - fprintf(stderr, "shot option can only be used with delay option\n"); - ret = 1; - goto end; - } - else if (compare_files && argc - args != 2) - { - fprintf(stderr, "Expected two files to compare as last arguments..\n"); - ecore_getopt_help(stderr, &optdesc); - ret = 1; - goto end; - } - - Lists_st *list = NULL; - if (clean || delay || list_get) - { - rec_file = argv[args]; - Timer_Data td; - list = read_events(rec_file, &td); - } - if (compare_files) - { - comp1 = argv[args]; - comp2 = argv[args+1]; - } - - if (clean) - { - Variant_st *v; - Eina_List *itr, *itr2; - EINA_LIST_FOREACH_SAFE(list->variant_list, itr, itr2, v) - { - if (!evt_time_get(0, v)) - list->variant_list = eina_list_remove_list(list->variant_list, itr); - else - { - if (_is_hook_duplicate(v, eina_list_data_get(eina_list_prev(itr)))) - list->variant_list = eina_list_remove_list(list->variant_list, itr); - } - } - if (!list->first_timestamp) - { - list->first_timestamp = evt_time_get(0, eina_list_data_get(list->variant_list)); - } - write_file = EINA_TRUE; - } - - if (delay) - { - if (!shot) - { - if (!list->first_timestamp) - { - list->first_timestamp = evt_time_get(0, eina_list_data_get(list->variant_list)); - } - list->first_timestamp -= delay; - } - else - { - Variant_st *v; - Eina_List *itr; - unsigned int cur_shot = 0; - EINA_LIST_FOREACH(list->variant_list, itr, v) - { - if (tsuite_event_mapping_type_get(v->t.type) == TSUITE_EVENT_TAKE_SHOT) - { - cur_shot++; - if (cur_shot == shot) - { - take_screenshot *t = v->data; - t->timestamp += delay; - break; - } - } - } - } - write_file = EINA_TRUE; - } - - if (list_get) - { - Variant_st *v; - Eina_List *itr; - printf("First timestamp: "); - if (list->first_timestamp) printf("%u\n", list->first_timestamp); - else printf("undefined\n"); - EINA_LIST_FOREACH(list->variant_list, itr, v) - { - char specific_output[1024]; - unsigned int timestamp = evt_time_get(0, v); - if (!timestamp) printf("BAD_TIME: "); - else printf("%.3f: ", (list->first_timestamp ? timestamp - list->first_timestamp : timestamp) / 1000.0); - printf("%s", _event_name_get(v)); - _event_specific_info_get(v, specific_output); - if (*specific_output) printf(" - %s", specific_output); - printf("\n"); - } - } - - if (compare_files) - { - const char *ext = strrchr(comp1, '.'); - if (!ext) - { - fprintf(stderr, "Extension required\n"); - goto end; - } - if (!strcmp(ext, ".eet")) - { - if (!objects_files_compare(comp1, comp2, EINA_TRUE)) - { - fprintf(stderr, "Failed objects comparing\n"); - } - } - else - { - char buf[1024]; - - /* FIXME: Clean up. */ - snprintf(buf, sizeof(buf), - "compare '%s' '%s' 'comp_file%s'", - comp1, comp2, ext); - if (system(buf)) - { - fprintf(stderr, "Failed image comparing '%s' and '%s'\n", comp1, comp2); - } - } - } - - if (rec_file && write_file) write_events(rec_file, list); - -end: - ecore_shutdown(); - - return ret; -} diff --git a/src/bin/inspect.c b/src/bin/inspect.c new file mode 100644 index 0000000..a4d8f5b --- /dev/null +++ b/src/bin/inspect.c @@ -0,0 +1,800 @@ +#ifndef EFL_BETA_API_SUPPORT +#define EFL_BETA_API_SUPPORT +#endif +#ifndef EFL_EO_API_SUPPORT +#define EFL_EO_API_SUPPORT +#endif +#include +#include +#include +#include + +#include "tsuite_file_data.h" + +typedef struct +{ + int w; + int h; + void *pixels; + int pixels_len; +} Exactness_Image; + +typedef struct +{ + void *p1; + void *p2; +} _Two_Ptrs; + +typedef struct +{ + Lists_st *scn; +// Exactness_Scenario *scn; + Eina_List *imgs; /* List of Exactness_Image */ +} Exactness_Unit; + +static Eo *_main_box = NULL; +static Eina_List *_gls = NULL; +static Eina_List *_units = NULL; + +static Elm_Genlist_Item_Class *_grp_itc = NULL, *_scn_itc = NULL, *_img_itc = NULL; +static Elm_Genlist_Item_Class *_comp_scn_itc = NULL, *_comp_img_itc = NULL; + +static const char * +_event_name_get(const Variant_st *v) +{ + switch(tsuite_event_mapping_type_get(v->t.type)) + { + case TSUITE_EVENT_MOUSE_IN: return "Mouse In"; + case TSUITE_EVENT_MOUSE_OUT: return "Mouse Out"; + case TSUITE_EVENT_MOUSE_DOWN: return "Mouse Down"; + case TSUITE_EVENT_MOUSE_UP: return "Mouse Up"; + case TSUITE_EVENT_MOUSE_MOVE: return "Mouse Move"; + case TSUITE_EVENT_MOUSE_WHEEL: return "Mouse Wheel"; + case TSUITE_EVENT_MULTI_DOWN: return "Multi Down"; + case TSUITE_EVENT_MULTI_UP: return "Multi Up"; + case TSUITE_EVENT_MULTI_MOVE: return "Multi Move"; + case TSUITE_EVENT_KEY_DOWN: return "Key Down"; + case TSUITE_EVENT_KEY_UP: return "Key Up"; + case TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE: return "Key Down with Keycode"; + case TSUITE_EVENT_KEY_UP_WITH_KEYCODE: return "Key Up with Keycode"; + case TSUITE_EVENT_TAKE_SHOT: return "Take shot"; + default: return NULL; + } +} + +static int +_event_struct_len_get(Tsuite_Event_Type type) +{ + switch(type) + { + case TSUITE_EVENT_MOUSE_IN: case TSUITE_EVENT_MOUSE_OUT: return sizeof(mouse_in_mouse_out); + case TSUITE_EVENT_MOUSE_DOWN: case TSUITE_EVENT_MOUSE_UP: return sizeof(mouse_down_mouse_up); + case TSUITE_EVENT_MOUSE_MOVE: return sizeof(mouse_move); + case TSUITE_EVENT_MOUSE_WHEEL: return sizeof(mouse_wheel); + case TSUITE_EVENT_MULTI_DOWN: case TSUITE_EVENT_MULTI_UP: return sizeof(multi_move); + case TSUITE_EVENT_MULTI_MOVE: return sizeof(multi_event); + case TSUITE_EVENT_KEY_DOWN: case TSUITE_EVENT_KEY_UP: return sizeof(key_down_key_up); + case TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE: case TSUITE_EVENT_KEY_UP_WITH_KEYCODE: return sizeof(key_down_key_up_with_keycode); + case TSUITE_EVENT_TAKE_SHOT: return sizeof(take_screenshot); + default: return 0; + } +} + +static void +_event_specific_info_get(const Variant_st *v, char output[1024]) +{ + switch(tsuite_event_mapping_type_get(v->t.type)) + { + case TSUITE_EVENT_MOUSE_DOWN: + { + mouse_down_mouse_up *t = v->data; + sprintf(output, "Button %d Flags %d", t->b, t->flags); + break; + } + case TSUITE_EVENT_MOUSE_UP: + { + mouse_down_mouse_up *t = v->data; + sprintf(output, "Button %d Flags %d", t->b, t->flags); + break; + } + case TSUITE_EVENT_MOUSE_MOVE: + { + mouse_move *t = v->data; + sprintf(output, "X %d Y %d", t->x, t->y); + break; + } + case TSUITE_EVENT_MOUSE_WHEEL: + { + mouse_wheel *t = v->data; + sprintf(output, "Direction %d Z %d", t->direction, t->z); + break; + } + case TSUITE_EVENT_MULTI_DOWN: case TSUITE_EVENT_MULTI_UP: + { + multi_event *t = v->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 TSUITE_EVENT_MULTI_MOVE: + { + multi_move *t = v->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 TSUITE_EVENT_KEY_UP: case TSUITE_EVENT_KEY_DOWN: + { + key_down_key_up *t = v->data; + sprintf(output, "Keyname %s Key %s String %s Compose %s", + t->keyname, t->key, t->string, t->compose); + break; + } + case TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE: case TSUITE_EVENT_KEY_UP_WITH_KEYCODE: + { + key_down_key_up_with_keycode *t = v->data; + sprintf(output, "Keyname %s Key %s String %s Compose %s Keycode %d", + t->keyname, t->key, t->string, t->compose, t->keycode); + break; + } + default: + { + output[0] = '\0'; + break; + } + } +} + +static const Ecore_Getopt optdesc = { + "exactness_inspect", + "%prog [options] [ | ]", + 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 events."), + ECORE_GETOPT_STORE_TRUE('l', "list", "List the events of the given recording."), + ECORE_GETOPT_STORE_TRUE('C', "compare", "Compare given files (images files or objects eet files)."), + ECORE_GETOPT_STORE_STR('o', "compare_output", "Output of the comparison."), + 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 + } +}; + +static Eina_Bool +_is_hook_duplicate(const Variant_st *cur_v, const Variant_st *prev_v) +{ + if (!prev_v) return EINA_FALSE; + Tsuite_Event_Type cur_type = tsuite_event_mapping_type_get(cur_v->t.type); + Tsuite_Event_Type prev_type = tsuite_event_mapping_type_get(prev_v->t.type); + if (cur_type == prev_type && + !memcmp(cur_v->data, prev_v->data, _event_struct_len_get(cur_type))) return EINA_TRUE; + return EINA_FALSE; +} + +static Exactness_Image * +_pixels_compare(Exactness_Image *img1, Exactness_Image *img2, Eina_Bool *has_diff) +{ + Exactness_Image *imgO = malloc(sizeof(*imgO)); + int w, h; + int *pxs1, *pxs2, *pxsO; + int w1 = img1 ? img1->w : 0, h1 = img1 ? img1->h : 0; + int w2 = img2 ? img2->w : 0, h2 = img2 ? img2->h : 0; + imgO->w = MAX(w1, w2); + imgO->h = MAX(h1, h2); + if (has_diff) *has_diff = EINA_FALSE; + if (!imgO->w || !imgO->h) + { + free(imgO); + return NULL; + } + imgO->pixels_len = imgO->w * imgO->h *4; + imgO->pixels = malloc(imgO->pixels_len); + + pxs1 = img1 ? img1->pixels : NULL; + pxs2 = img2 ? img2->pixels : NULL; + pxsO = imgO->pixels; + + for (w = 0; w < imgO->w; w++) + { + for (h = 0; h < imgO->h; h++) + { + Eina_Bool valid1 = w <= w1 && h <= h1; + Eina_Bool valid2 = w <= w2 && h <= h2; + int px1 = valid1 ? pxs1[h * w1 + w] : 0; + int px2 = valid2 ? pxs2[h * w2 + w] : 0; + int r1 = (px1 & 0x00FF0000) >> 16; + int r2 = (px2 & 0x00FF0000) >> 16; + int g1 = (px1 & 0x0000FF00) >> 8; + int g2 = (px2 & 0x0000FF00) >> 8; + int b1 = (px1 & 0x000000FF); + int b2 = (px2 & 0x000000FF); + int new_r, new_g, new_b; + if (valid1 || valid2) + { + if (px1 != px2) + { + new_r = 0xFF; + new_g = ((g1 + g2) >> 1) >> 2; + new_b = ((b1 + b2) >> 1) >> 2; + if (has_diff) *has_diff = EINA_TRUE; + } + else + { + new_r = (((r1 + r2) >> 1) >> 2) + 0xC0; + new_g = (((g1 + g2) >> 1) >> 2) + 0xC0; + new_b = (((b1 + b2) >> 1) >> 2) + 0xC0; + } + } + else + { + new_r = new_g = new_b = 0x0; + } + pxsO[h * imgO->w + w] = 0xFF000000 | new_r << 16 | new_g << 8 | new_b; + } + } + return imgO; +} + +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); + 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 *obj EINA_UNUSED, const char *part EINA_UNUSED) +{ + return strdup(data); +} + +static char * +_scn_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED) +{ + Variant_st *v = data; + Eina_Strbuf *buf = eina_strbuf_new(); + char *ret = NULL; + unsigned int timestamp = evt_time_get(0, v); + char specific_output[1024]; + if (!timestamp) eina_strbuf_append(buf, "BAD_TIME: "); + else eina_strbuf_append_printf(buf, "%.3f: ", timestamp / 1000.0); + eina_strbuf_append_printf(buf, "%s", _event_name_get(v)); + _event_specific_info_get(v, specific_output); + if (*specific_output) eina_strbuf_append_printf(buf, " - %s", specific_output); + ret = eina_strbuf_string_steal(buf); + eina_strbuf_free(buf); + return ret; +} + +static char * +_comp_scn_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED) +{ + _Two_Ptrs *vv = data; + Variant_st *v1 = vv->p1; + Variant_st *v2 = vv->p2; + int tm1 = evt_time_get(0, v1); + int tm2 = evt_time_get(0, v2); + Tsuite_Event_Type t1 = tsuite_event_mapping_type_get(v1->t.type); + Tsuite_Event_Type t2 = tsuite_event_mapping_type_get(v2->t.type); + Eina_Strbuf *buf = eina_strbuf_new(); + char *ret = NULL; + + if (tm1 != tm2) eina_strbuf_append_printf(buf, "[%.3f/%.3f]: ", tm1/1000.0, tm2/1000.0); + else eina_strbuf_append_printf(buf, "%.3f: ", tm1 / 1000.0); + + if (t1 != t2) + eina_strbuf_append_printf(buf, "[%s/%s] - XXXXXX", _event_name_get(v1), _event_name_get(v2)); + else + { + char params1[1024]; + char params2[2024]; + _event_specific_info_get(v1, params1); + _event_specific_info_get(v2, params2); + + eina_strbuf_append_printf(buf, "%s", _event_name_get(v1)); + if (*params1 || *params2) + { + if (strcmp(params1, params2)) + eina_strbuf_append_printf(buf, " - [%s/%s]", params1, params2); + else + eina_strbuf_append_printf(buf, " - %s", params1); + } + } + + ret = eina_strbuf_string_steal(buf); + eina_strbuf_free(buf); + return ret; +} + +static Evas_Object * +_img_content_get(void *data, Evas_Object *obj, const char *part) +{ + if (strcmp(part, "elm.swallow.content")) return NULL; + Exactness_Image *ex_img = data; + Eo *img = elm_image_add(obj); + Eo *evas_img = elm_image_object_get(img); + 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 Evas_Object * +_comp_img_content_get(void *data, Evas_Object *obj, const char *part) +{ + if (strcmp(part, "elm.swallow.content")) return NULL; + _Two_Ptrs *vv = data; + Exactness_Image *img1 = vv->p1; + Exactness_Image *img2 = vv->p2; + Exactness_Image *imgO = _pixels_compare(img1, img2, NULL); + + Eo *img = elm_image_add(obj); + Eo *evas_img = elm_image_object_get(img); + evas_object_image_size_set(evas_img, imgO->w, imgO->h); + evas_object_image_data_set(evas_img, imgO->pixels); + evas_object_size_hint_min_set(img, ELM_SCALE_SIZE(300), ELM_SCALE_SIZE(300)); + + return img; +} + +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"; + _scn_itc->func.text_get = _scn_text_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 (!_comp_scn_itc) + { + _comp_scn_itc = elm_genlist_item_class_new(); + _comp_scn_itc->item_style = "default"; + _comp_scn_itc->func.text_get = _comp_scn_text_get; + } + + if (!_comp_img_itc) + { + _comp_img_itc = elm_genlist_item_class_new(); + _comp_img_itc->item_style = "full"; + _comp_img_itc->func.content_get = _comp_img_content_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 +_gui_unit_display(Exactness_Unit *unit1, Exactness_Unit *unit2, int position) +{ + Eina_List *itr1, *itr2; + Eo *gl; + + gl = elm_genlist_add(_main_box); + elm_genlist_homogeneous_set(gl, EINA_TRUE); + evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL); + efl_gfx_visible_set(gl, EINA_TRUE); + _gls = eina_list_append(_gls, gl); + + if (position == -1) elm_box_pack_end(_main_box, gl); + else if (position == 0) elm_box_pack_start(_main_box, gl); + else + { + Eina_List *children = elm_box_children_get(_main_box); + Eo *before = eina_list_nth(children, position - 1); + elm_box_pack_after(_main_box, gl, before); + eina_list_free(children); + } + + if (unit2) + { + elm_interface_scrollable_vbar_drag_cb_set(gl, _comp_gl_dragged_cb); + } + _itc_init(); + + itr1 = unit1 && unit1->scn ? unit1->scn->variant_list : NULL; + itr2 = unit2 && unit2->scn ? unit2->scn->variant_list : NULL; + + if (itr1) + elm_genlist_item_append(gl, _grp_itc, "Scenario", NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + while (itr1 || itr2) + { + Variant_st *v1 = itr1 ? eina_list_data_get(itr1) : NULL; + if (unit2) + { + Variant_st *v2 = itr2 ? eina_list_data_get(itr2) : NULL; + _Two_Ptrs *vv = malloc(sizeof(*vv)); + vv->p1 = v1; + vv->p2 = v2; + elm_genlist_item_append(gl, _comp_scn_itc, vv, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + } + else + { + elm_genlist_item_append(gl, _scn_itc, v1, 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) + elm_genlist_item_append(gl, _grp_itc, "Images", NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + while (itr1 || itr2) + { + Exactness_Image *img1 = itr1 ? eina_list_data_get(itr1) : NULL; + if (unit2) + { + Exactness_Image *img2 = itr2 ? eina_list_data_get(itr2) : NULL; + _Two_Ptrs *vv = malloc(sizeof(*vv)); + vv->p1 = img1; + vv->p2 = img2; + elm_genlist_item_append(gl, _comp_img_itc, vv, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + } + else + { + elm_genlist_item_append(gl, _img_itc, img1, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + } + if (itr1) itr1 = eina_list_next(itr1); + if (itr2) itr2 = eina_list_next(itr2); + } +} + +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; + ex_img->pixels_len = w * h * 4; + len = ex_img->pixels_len; + 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; +} + +int +main(int argc, char *argv[]) +{ + const char *ext = NULL; + const char *rec_file = NULL; + char *compare_output = 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 gui_needed = EINA_TRUE; + 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_STR(compare_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; + } + else if (want_quit) + { + goto end; + } + else if ((clean || delay || shot || list_get) && args == argc) + { + fprintf(stderr, "Expected rec file as the last argument.\n"); + ecore_getopt_help(stderr, &optdesc); + goto end; + } + else if (shot && !delay) + { + fprintf(stderr, "shot option can only be used with delay option.\n"); + goto end; + } + else 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; + } + + Lists_st *list = NULL; + if (clean || delay || list_get) + { + rec_file = argv[args]; + Timer_Data td; + gui_needed = EINA_FALSE; + list = read_events(rec_file, &td); + } + else + { + int arg; + if (compare_output) gui_needed = EINA_FALSE; + for (arg = args; arg < argc; arg++) + { + if (!ext) ext = strrchr(argv[arg], '.'); + if (!ext) + { + fprintf(stderr, "Extension required\n"); + goto end; + } + if (!strcmp(ext, ".rec")) + { + Exactness_Unit *ex_unit = calloc(1, sizeof(*ex_unit)); + Timer_Data td; + Variant_st *v; + Eina_List *itr; + list = read_events(argv[arg], &td); + if (!list) + { + fprintf(stderr, "Issue while reading %s\n", argv[arg]); + goto end; + } + EINA_LIST_FOREACH(list->variant_list, itr, v) + { + unsigned int tm = evt_time_get(0, v); + if (tm) evt_time_set(tm - list->first_timestamp, v); + } + ex_unit->scn = list; + _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); + _units = eina_list_append(_units, ex_unit); + } + } + } + + if (clean) + { + Variant_st *v; + Eina_List *itr, *itr2; + EINA_LIST_FOREACH_SAFE(list->variant_list, itr, itr2, v) + { + if (!evt_time_get(0, v)) + list->variant_list = eina_list_remove_list(list->variant_list, itr); + else + { + if (_is_hook_duplicate(v, eina_list_data_get(eina_list_prev(itr)))) + list->variant_list = eina_list_remove_list(list->variant_list, itr); + } + } + if (!list->first_timestamp) + { + list->first_timestamp = evt_time_get(0, eina_list_data_get(list->variant_list)); + } + write_file = EINA_TRUE; + } + + if (delay) + { + if (!shot) + { + if (!list->first_timestamp) + { + list->first_timestamp = evt_time_get(0, eina_list_data_get(list->variant_list)); + } + list->first_timestamp -= delay; + } + else + { + Variant_st *v; + Eina_List *itr; + unsigned int cur_shot = 0; + EINA_LIST_FOREACH(list->variant_list, itr, v) + { + if (tsuite_event_mapping_type_get(v->t.type) == TSUITE_EVENT_TAKE_SHOT) + { + cur_shot++; + if (cur_shot == shot) + { + take_screenshot *t = v->data; + t->timestamp += delay; + break; + } + } + } + } + write_file = EINA_TRUE; + } + + if (list_get) + { + Variant_st *v; + Eina_List *itr; + printf("First timestamp: "); + if (list->first_timestamp) printf("%u\n", list->first_timestamp); + else printf("undefined\n"); + EINA_LIST_FOREACH(list->variant_list, itr, v) + { + char specific_output[1024]; + unsigned int timestamp = evt_time_get(0, v); + if (!timestamp) printf("BAD_TIME: "); + else printf("%.3f: ", (list->first_timestamp ? timestamp - list->first_timestamp : timestamp) / 1000.0); + printf("%s", _event_name_get(v)); + _event_specific_info_get(v, specific_output); + if (*specific_output) printf(" - %s", specific_output); + printf("\n"); + } + } + + if (compare_files && compare_output) + { + Exactness_Unit *unit1 = NULL, *unit2 = NULL; + Eina_List *itr; + Exactness_Unit *unit; + EINA_LIST_FOREACH(_units, itr, unit) + { + if (!unit1) unit1 = unit; + else if (!unit2) unit2 = unit; + else + { + fprintf(stderr, "Too much files to compare (only 2)."); + goto end; + } + } + + if (!strcmp(ext, ".png")) + { + Eina_Bool has_diff = EINA_FALSE; + Exactness_Image *ex_img1 = eina_list_data_get(unit1->imgs); + Exactness_Image *ex_img2 = eina_list_data_get(unit2->imgs); + Exactness_Image *ex_imgO = _pixels_compare(ex_img1, ex_img2, &has_diff); + + if (has_diff) + { + Ecore_Evas *ee; + Eo *e, *img; + 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, compare_output, NULL, NULL); + ecore_evas_free(ee); + goto end; + } + } + } + + ret = 0; + if (rec_file && write_file) write_events(rec_file, list); + + if (gui_needed) + { + Eina_List *itr; + Exactness_Unit *unit, *unit1 = NULL, *unit2 = NULL; + Eina_Bool need_compare = compare_files && eina_list_count(_units) == 2; + _gui_win_create(); + EINA_LIST_FOREACH(_units, itr, unit) + { + if (need_compare) + { + if (!unit1) unit1 = unit; + else unit2 = unit; + } + _gui_unit_display(unit, NULL, -1); + } + if (need_compare) + { + _gui_unit_display(unit1, unit2, 1); + } + elm_run(); + } + +end: + elm_shutdown(); + eet_shutdown(); + ecore_shutdown(); + ecore_evas_shutdown(); + + return ret; +} diff --git a/src/lib/tsuite_common.c b/src/lib/tsuite_common.c index d210965..df980d1 100644 --- a/src/lib/tsuite_common.c +++ b/src/lib/tsuite_common.c @@ -81,3 +81,97 @@ evt_time_get(unsigned int tm, Variant_st *v) } } +void +evt_time_set(unsigned int tm, Variant_st *v) +{ + switch(tsuite_event_mapping_type_get(v->t.type)) + { + case TSUITE_EVENT_MOUSE_IN: + { + mouse_in_mouse_out *t = v->data; + t->timestamp = tm; + break; + } + case TSUITE_EVENT_MOUSE_OUT: + { + mouse_in_mouse_out *t = v->data; + t->timestamp = tm; + break; + } + case TSUITE_EVENT_MOUSE_DOWN: + { + mouse_down_mouse_up *t = v->data; + t->timestamp = tm; + break; + } + case TSUITE_EVENT_MOUSE_UP: + { + mouse_down_mouse_up *t = v->data; + t->timestamp = tm; + break; + } + case TSUITE_EVENT_MOUSE_MOVE: + { + mouse_move *t = v->data; + t->timestamp = tm; + break; + } + case TSUITE_EVENT_MOUSE_WHEEL: + { + mouse_wheel *t = v->data; + t->timestamp = tm; + break; + } + case TSUITE_EVENT_MULTI_DOWN: + { + multi_event *t = v->data; + t->timestamp = tm; + break; + } + case TSUITE_EVENT_MULTI_UP: + { + multi_event *t = v->data; + t->timestamp = tm; + break; + } + case TSUITE_EVENT_MULTI_MOVE: + { + multi_move *t = v->data; + t->timestamp = tm; + break; + } + case TSUITE_EVENT_KEY_DOWN: + { + key_down_key_up *t = v->data; + t->timestamp = tm; + break; + } + case TSUITE_EVENT_KEY_UP: + { + key_down_key_up *t = v->data; + t->timestamp = tm; + break; + } + case TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE: + { + key_down_key_up_with_keycode *t = v->data; + t->timestamp = tm; + break; + } + case TSUITE_EVENT_KEY_UP_WITH_KEYCODE: + { + key_down_key_up_with_keycode *t = v->data; + t->timestamp = tm; + break; + } + case TSUITE_EVENT_TAKE_SHOT: + { + take_screenshot *t = v->data; + t->timestamp = tm; + break; + } + default: /* All non-input events are not handeled */ + break; + } +} + diff --git a/src/lib/tsuite_file_data.h b/src/lib/tsuite_file_data.h index 831828d..d4d0ecd 100644 --- a/src/lib/tsuite_file_data.h +++ b/src/lib/tsuite_file_data.h @@ -277,4 +277,5 @@ EAPI Lists_st * free_events(Lists_st *st, Eina_Bool recording); EAPI void write_events(const char *filename, Lists_st *vr_list); EAPI Lists_st *read_events(const char *filename, Timer_Data *td); EAPI unsigned int evt_time_get(unsigned int tm, Variant_st *v); +EAPI void evt_time_set(unsigned int tm, Variant_st *v); #endif