From 5a6de029693ecd1cc2fc52a3ab1c187ecbec21ba Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Mon, 15 Mar 2010 18:34:04 +0000 Subject: [PATCH] Add elm_thumb object to Elementary. The elm_thumb object interacts with ethumb to create a thumbnail. By: Rafael Fonseca SVN revision: 47240 --- configure.ac | 17 ++ data/themes/default.edc | 120 ++++++++ src/bin/Makefile.am | 4 +- src/bin/test.c | 2 + src/bin/test_thumb.c | 68 +++++ src/lib/Elementary.h.in | 38 +++ src/lib/Makefile.am | 6 +- src/lib/elm_thumb.c | 733 ++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 985 insertions(+), 3 deletions(-) create mode 100644 src/bin/test_thumb.c create mode 100644 src/lib/elm_thumb.c diff --git a/configure.ac b/configure.ac index 51ed17c..25d9dcc 100644 --- a/configure.ac +++ b/configure.ac @@ -363,6 +363,22 @@ if test "x$want_elementary_eweather" = "xyes" -a "x$have_elementary_eweather" = fi AC_SUBST(ELM_EWEATHER_DEF) +ELM_ETHUMB_DEF="#undef" +have_elementary_ethumb="no" +PKG_CHECK_MODULES([ELEMENTARY_ETHUMB], + [ + ethumb_client + ], + [ + AC_DEFINE(HAVE_ELEMENTARY_ETHUMB, 1, [Ethumb support for Elementary]) + have_elementary_ethumb="yes" + ELM_ETHUMB_DEF="#define" + requirement_elm="ethumb ${requirement_elm}" + ], + [have_elementary_ethumb="no"] +) +AC_SUBST(ELM_ETHUMB_DEF) + ELM_ALLOCA_H_DEF="#undef" AC_CHECK_HEADER(alloca.h, [ELM_ALLOCA_H_DEF="#define"]) AC_SUBST(ELM_ALLOCA_H_DEF) @@ -436,6 +452,7 @@ echo " Features:" echo " EDBus..............: ${have_elementary_edbus}" echo " EFreet.............: ${have_elementary_efreet}" echo " EWeather...........: ${have_elementary_eweather}" +echo " Ethumb.............: ${have_elementary_ethumb}" echo echo " edje_cc..............: ${edje_cc}" echo diff --git a/data/themes/default.edc b/data/themes/default.edc index be7310c..01825e3 100644 --- a/data/themes/default.edc +++ b/data/themes/default.edc @@ -6781,6 +6781,126 @@ collections { } /////////////////////////////////////////////////////////////////////////////// + group { name: "elm/thumb/base/default"; + images { + image: "frame_1.png" COMP; + image: "frame_2.png" COMP; + image: "dia_grad.png" COMP; + image: "busy-1.png" COMP; + image: "busy-2.png" COMP; + image: "busy-3.png" COMP; + image: "busy-4.png" COMP; + image: "busy-5.png" COMP; + image: "busy-6.png" COMP; + image: "busy-7.png" COMP; + image: "busy-8.png" COMP; + image: "busy-9.png" COMP; + } + parts { + part { name: "base0"; + mouse_events: 0; + description { state: "default" 0.0; + image.normal: "dia_grad.png"; + rel1.to: "over"; + rel2.to: "over"; + fill { + smooth: 0; + size { + relative: 0.0 1.0; + offset: 64 0; + } + } + } + } + part { name: "base"; + mouse_events: 0; + description { state: "default" 0.0; + image { + normal: "frame_2.png"; + border: 5 5 32 26; + middle: 0; + } + fill.smooth : 0; + } + } + part { name: "clip"; + mouse_events: 0; + type: RECT; + description { state: "default" 0.0; + rel1.offset: 4 4; + rel2.offset: -5 -5; + color: 255 255 255 255; + } + } + part { name: "elm.swallow.content"; + type: SWALLOW; + clip_to: "clip"; + description { state: "default" 0.0; + rel1.offset: 4 4; + rel2.offset: -5 -5; + } + } + part { name: "progress"; + mouse_events: 0; + + clip_to: "clip"; + description { state: "default" 0.0; + min: 32 32; + max: 32 32; + visible: 0; + aspect: 1.0 1.0; + aspect_preference: BOTH; + } + description { state: "pulse" 0.0; + inherit: "default" 0.0; + visible: 1; + image { + normal: "busy-9.png"; + tween: "busy-1.png"; + tween: "busy-2.png"; + tween: "busy-3.png"; + tween: "busy-4.png"; + tween: "busy-5.png"; + tween: "busy-6.png"; + tween: "busy-7.png"; + tween: "busy-8.png"; + border: 7 7 7 7; + } + } + } + part { name: "over"; + mouse_events: 0; + description { state: "default" 0.0; + rel1.offset: 4 4; + rel2.offset: -5 -5; + image { + normal: "frame_1.png"; + border: 2 2 28 22; + middle: 0; + } + fill.smooth: 0; + } + } + programs { + program { name: "start_pulse"; + signal: "elm,state,pulse,start"; + source: "elm"; + action: STATE_SET "pulse" 0.0; + target: "progress"; + transition: LINEAR 0.5; + after: "start_pulse"; + } + program { name: "stop_pulse"; + signal: "elm,state,pulse,stop"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "progress"; + } + } + } + } + +/////////////////////////////////////////////////////////////////////////////// group { name: "elm/icon/home/default"; min: 32 32; images.image: "icon_home.png" COMP; parts { part { name: "base"; description { state: "default" 0.0; aspect: 1.0 1.0; aspect_preference: BOTH; diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index d51c132..565aa3a 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -15,7 +15,8 @@ AM_CPPFLAGS = \ @ELEMENTARY_WINCE_CFLAGS@ \ @ELEMENTARY_EDBUS_CFLAGS@ \ @ELEMENTARY_EFREET_CFLAGS@ \ -@ELEMENTARY_EWEATHER_CFLAGS@ +@ELEMENTARY_EWEATHER_CFLAGS@ \ +@ELEMENTARY_ETHUMB_CFLAGS@ if ELEMENTARY_WINDOWS_BUILD AM_CPPFLAGS += -DELEMENTARY_BUILD @@ -61,6 +62,7 @@ test_spinner.c \ test_index.c \ test_photocam.c \ test_photo.c \ +test_thumb.c \ test_icon_desktops.c \ test_notify.c \ test_slideshow.c \ diff --git a/src/bin/test.c b/src/bin/test.c index 54a0795..6641011 100644 --- a/src/bin/test.c +++ b/src/bin/test.c @@ -50,6 +50,7 @@ void test_spinner(void *data, Evas_Object *obj, void *event_info); void test_index(void *data, Evas_Object *obj, void *event_info); void test_photocam(void *data, Evas_Object *obj, void *event_info); void test_photo(void *data, Evas_Object *obj, void *event_info); +void test_thumb(void *data, Evas_Object *obj, void *event_info); void test_icon_desktops(void *data, Evas_Object *obj, void *event_info); void test_notify(void *data, Evas_Object *obj, void *event_info); void test_slideshow(void *data, Evas_Object *obj, void *event_info); @@ -197,6 +198,7 @@ my_win_main(void) elm_list_item_append(li, "Index", NULL, NULL, test_index, NULL); elm_list_item_append(li, "Photocam", NULL, NULL, test_photocam, NULL); elm_list_item_append(li, "Photo", NULL, NULL, test_photo, NULL); + elm_list_item_append(li, "Thumb", NULL, NULL, test_thumb, NULL); elm_list_item_append(li, "Icon Desktops", NULL, NULL, test_icon_desktops, NULL); elm_list_item_append(li, "Notify", NULL, NULL, test_notify, NULL); elm_list_item_append(li, "Slideshow", NULL, NULL, test_slideshow, NULL); diff --git a/src/bin/test_thumb.c b/src/bin/test_thumb.c new file mode 100644 index 0000000..d55242b --- /dev/null +++ b/src/bin/test_thumb.c @@ -0,0 +1,68 @@ +#include +#ifndef ELM_LIB_QUICKLAUNCH +void +test_thumb(void *data, Evas_Object *obj, void *event_info) +{ + Evas_Object *win, *bg, *sc, *tb, *th; + int i, j, n; + char buf[PATH_MAX]; + const char *img[9] = + { + "panel_01.jpg", + "plant_01.jpg", + "rock_01.jpg", + "rock_02.jpg", + "sky_01.jpg", + "sky_02.jpg", + "sky_03.jpg", + "sky_04.jpg", + "wood_01.jpg", + }; + + elm_need_ethumb(); + + win = elm_win_add(NULL, "thumb", ELM_WIN_BASIC); + elm_win_title_set(win, "Thumb"); + elm_win_autodel_set(win, 1); + + bg = elm_bg_add(win); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, bg); + evas_object_show(bg); + + tb = elm_table_add(win); + evas_object_size_hint_weight_set(tb, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + + n = 0; + for (j = 0; j < 12; j++) + { + for (i = 0; i < 12; i++) + { + th = elm_thumb_add(win); + snprintf(buf, sizeof(buf), "%s/images/%s", PACKAGE_DATA_DIR, + img[n]); + n = (n + 1) % 9; + elm_thumb_file_set(th, buf, img[n]); + evas_object_size_hint_weight_set(th, EVAS_HINT_EXPAND, + EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(th, EVAS_HINT_FILL, + EVAS_HINT_FILL); + elm_thumb_align_set(th, 0.5, 0.5); + elm_thumb_keep_aspect_set(th, EINA_TRUE); + elm_table_pack(tb, th, i, j, 1, 1); + evas_object_show(th); + } + } + + sc = elm_scroller_add(win); + evas_object_size_hint_weight_set(sc, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, sc); + + elm_scroller_content_set(sc, tb); + evas_object_show(tb); + evas_object_show(sc); + + evas_object_resize(win, 600, 600); + evas_object_show(win); +} +#endif diff --git a/src/lib/Elementary.h.in b/src/lib/Elementary.h.in index 036e191..b507a35 100644 --- a/src/lib/Elementary.h.in +++ b/src/lib/Elementary.h.in @@ -17,6 +17,7 @@ @ELM_WINCE_DEF@ ELM_WINCE @ELM_EDBUS_DEF@ ELM_EDBUS @ELM_EFREET_DEF@ ELM_EFREET +@ELM_ETHUMB_DEF@ ELM_ETHUMB @ELM_ALLOCA_H_DEF@ ELM_ALLOCA_H @ELM_LIBINTL_H_DEF@ ELM_LIBINTL_H @@ -81,6 +82,10 @@ # include #endif +#ifdef ELM_ETHUMB +# include +#endif + #ifdef EAPI # undef EAPI #endif @@ -118,6 +123,8 @@ extern "C" { #define ELM_PI 3.14159265358979323846 /**************************************************************************/ + EAPI extern int ELM_ECORE_EVENT_ETHUMB_CONNECT; + /* Objects */ typedef enum _Elm_Win_Type { @@ -181,6 +188,13 @@ extern "C" { ELM_POLICY_QUIT_LAST_WINDOW_CLOSED /**< quit when last window is closed */ } Elm_Policy_Quit; + typedef enum _Elm_Thumb_Animation_Setting + { + ELM_THUMB_ANIMATION_START = 0, /* Play animation once */ + ELM_THUMB_ANIMATION_LOOP, /* Keep playing animation until stop is requested */ + ELM_THUMB_ANIMATION_STOP + } Elm_Thumb_Animation_Setting; + #ifndef ELM_LIB_QUICKLAUNCH #define ELM_MAIN() int main(int argc, char **argv) {elm_init(argc, argv); return elm_main(argc, argv);} #else @@ -207,6 +221,7 @@ extern "C" { EAPI void elm_need_efreet(void); EAPI void elm_need_e_dbus(void); + EAPI void elm_need_ethumb(void); EAPI Eina_Bool elm_policy_set(unsigned int policy, int value); EAPI int elm_policy_get(unsigned int policy); @@ -682,6 +697,29 @@ extern "C" { * "clicked" - the user clicked the icon */ + EAPI Evas_Object *elm_thumb_add(Evas_Object *parent); + EAPI void elm_thumb_file_set(Evas_Object *obj, const char *file, const char *key); + EAPI void elm_thumb_file_get(Evas_Object *obj, const char **file, const char **key); + EAPI void elm_thumb_keep_aspect_set(Evas_Object *obj, Eina_Bool setting); + EAPI void elm_thumb_align_set(Evas_Object *obj, float x_align, float y_align); + EAPI void elm_thumb_align_get(Evas_Object *obj, float *x, float *y); + EAPI void elm_thumb_animate(Evas_Object *obj, Elm_Thumb_Animation_Setting s); + EAPI Eina_Bool elm_thumb_ethumb_client_connected(void); +#ifdef ELM_ETHUMB + EAPI Ethumb_Client *elm_thumb_ethumb_client_get(void); +#else + EAPI void *elm_thumb_ethumb_client_get(void); +#endif + /* smart callbacks called: + * "clicked" - the user clicked the thumb + * "clicked,double" - the user double clicked the thumb + * "press" - the user pressed the thumb + * "generate,start" - the thumbnail generation started + * "generate,stop" - the thumbnail generation stopped + * "generate,error" - the thumbnail generation failed + * "load,error" - the thumbnail image loading failed + */ + EAPI Evas_Object *elm_hoversel_add(Evas_Object *parent); EAPI void elm_hoversel_horizontal_set(Evas_Object *obj, Eina_Bool horizontal); EAPI void elm_hoversel_hover_parent_set(Evas_Object *obj, Evas_Object *parent); diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index f7000d1..d8a7b57 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -16,7 +16,8 @@ AM_CPPFLAGS = \ @ELEMENTARY_WIN32_CFLAGS@ \ @ELEMENTARY_WINCE_CFLAGS@ \ @ELEMENTARY_EDBUS_CFLAGS@ \ -@ELEMENTARY_EFREET_CFLAGS@ +@ELEMENTARY_EFREET_CFLAGS@ \ +@ELEMENTARY_ETHUMB_CFLAGS@ if ELEMENTARY_WINDOWS_BUILD AM_CPPFLAGS += -DELEMENTARY_BUILD @@ -71,6 +72,7 @@ elm_map.c \ elm_flip.c \ elm_conform.c \ elm_mapbuf.c \ +elm_thumb.c \ \ elc_notepad.c \ elc_anchorview.c \ @@ -90,5 +92,5 @@ els_icon.h libelementary_la_CFLAGS = -libelementary_la_LIBADD = @my_libs@ @dlopen_libs@ @ELEMENTARY_LIBS@ @ELEMENTARY_X_LIBS@ @ELEMENTARY_FB_LIBS@ @ELEMENTARY_SDL_LIBS@ @ELEMENTARY_WIN32_LIBS@ @ELEMENTARY_WINCE_LIBS@ @ELEMENTARY_EDBUS_LIBS@ @ELEMENTARY_EFREET_LIBS@ +libelementary_la_LIBADD = @my_libs@ @dlopen_libs@ @ELEMENTARY_LIBS@ @ELEMENTARY_X_LIBS@ @ELEMENTARY_FB_LIBS@ @ELEMENTARY_SDL_LIBS@ @ELEMENTARY_WIN32_LIBS@ @ELEMENTARY_WINCE_LIBS@ @ELEMENTARY_EDBUS_LIBS@ @ELEMENTARY_EFREET_LIBS@ @ELEMENTARY_ETHUMB_LIBS@ libelementary_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ diff --git a/src/lib/elm_thumb.c b/src/lib/elm_thumb.c new file mode 100644 index 0000000..8a42285 --- /dev/null +++ b/src/lib/elm_thumb.c @@ -0,0 +1,733 @@ +#include +#include "elm_priv.h" + +/** + * @defgroup Thumb Thumb + * + * A thumb object is used for displaying the thumbnail of an image or video. + * You must have compiled Elementary with Ethumb_Client support and the DBus + * service must be present and auto-activated in order to have thumbnails to + * be generated. + * + * Signals that you can add callbacks for are: + * + * clicked - This is called when a user has clicked the thumb without dragging + * around. + * + * clicked,double - This is called when a user has double-clicked the thumb. + * + * press - This is called when a user has pressed down the thumb. + * + * generate,start - The thumbnail generation started. + * + * generate,stop - The generation process stopped. + * + * generate,error - The generation failed. + * + * load,error - The thumbnail image loading failed. + */ + +typedef struct _Widget_Data Widget_Data; + +struct _Widget_Data +{ + Evas_Object *self; + struct { + Evas_Object *frm; + Evas_Object *view; + struct { + float x, y; + } align; + } children; + const char *file; + const char *key; + Ecore_Event_Handler *eeh; + int id; + Eina_Bool on_hold : 1; + Eina_Bool is_video : 1; + Eina_Bool is_generating : 1; + Eina_Bool keep_aspect : 1; +}; + +static const char *widtype = NULL; +static const char EDJE_SIGNAL_GENERATE_START[] = "elm,thumb,generate,start"; +static const char EDJE_SIGNAL_GENERATE_STOP[] = "elm,thumb,generate,stop"; +static const char EDJE_SIGNAL_GENERATE_ERROR[] = "elm,thumb,generate,error"; +static const char EDJE_SIGNAL_LOAD_ERROR[] = "elm,thumb,load,error"; +static const char EDJE_SIGNAL_PULSE_START[] = "elm,state,pulse,start"; +static const char EDJE_SIGNAL_PULSE_STOP[] = "elm,state,pulse,stop"; + +#ifdef HAVE_ELEMENTARY_ETHUMB +Ethumb_Client *_elm_ethumb_client = NULL; +#endif +Eina_Bool _elm_ethumb_connected = EINA_FALSE; + +EAPI int ELM_ECORE_EVENT_ETHUMB_CONNECT = 0; + +static void _thumb_geometry_set(Widget_Data *wd); + +static void +_del_hook(Evas_Object *obj) +{ + Widget_Data *wd = elm_widget_data_get(obj); + eina_stringshare_del(wd->file); + eina_stringshare_del(wd->key); + if (wd->eeh) + ecore_event_handler_del(wd->eeh); + free(wd); +} + +static void +_theme_hook(Evas_Object *obj) +{ + Widget_Data *wd = elm_widget_data_get(obj); + _elm_theme_set(wd->children.frm, "thumb", "base", elm_widget_style_get(obj)); +} + +#ifdef HAVE_ELEMENTARY_ETHUMB +static void +_mouse_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Widget_Data *wd = data; + Evas_Event_Mouse_Down *ev = event_info; + if (ev->button != 1) + return; + if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) + wd->on_hold = EINA_TRUE; + else + wd->on_hold = EINA_FALSE; + if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK) + evas_object_smart_callback_call(data, "clicked,double", NULL); + else + evas_object_smart_callback_call(data, "press", NULL); +} + +static void +_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + + Widget_Data *wd = data; + Evas_Event_Mouse_Up *ev = event_info; + if (ev->button != 1) + return; + if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) + wd->on_hold = EINA_TRUE; + else + wd->on_hold = EINA_FALSE; + if (!wd->on_hold) + evas_object_smart_callback_call(data, "clicked", NULL); + wd->on_hold = EINA_FALSE; +} + +static void +_finished_thumb(Widget_Data *wd, int id, const char *thumb_path, const char *thumb_key) +{ + int r; + Evas *evas; + + evas = evas_object_evas_get(wd->self); + if (wd->children.view) + evas_object_del(wd->children.view); + wd->children.view = NULL; + wd->id = id; + + if (wd->is_video && + ethumb_client_format_get(_elm_ethumb_client) == ETHUMB_THUMB_EET) + { + wd->children.view = edje_object_add(evas); + if (!wd->children.view) + { + ERR("could not create edje object"); + goto err; + } + if (!edje_object_file_set(wd->children.view, thumb_path, "movie/thumb")) + { + ERR("could not set file=%s key=%s for %s", thumb_path, thumb_key, + wd->file); + goto view_err; + } + } + else + { + wd->children.view = evas_object_image_filled_add(evas); + if (!wd->children.view) + { + ERR("could not create image object"); + goto err; + } + evas_object_image_file_set(wd->children.view, thumb_path, thumb_key); + r = evas_object_image_load_error_get(wd->children.view); + if (r != EVAS_LOAD_ERROR_NONE) + { + ERR("%s: %s", thumb_path, evas_load_error_str(r)); + goto view_err; + } + } + + elm_widget_sub_object_add(wd->self, wd->children.view); + edje_object_part_swallow(wd->children.frm, "elm.swallow.content", + wd->children.view); + edje_object_signal_emit(wd->children.frm, EDJE_SIGNAL_GENERATE_STOP, "elm"); + evas_object_smart_callback_call(wd->self, "generate,stop", NULL); + _thumb_geometry_set(wd); + return; + +view_err: + evas_object_del(wd->children.view); + wd->children.view = NULL; +err: + edje_object_signal_emit(wd->children.frm, EDJE_SIGNAL_LOAD_ERROR, "elm"); + evas_object_smart_callback_call(wd->self, "load,error", NULL); +} + +static void +_finished_thumb_cb(void *data, Ethumb_Client *c, int id, const char *file, const char *key, const char *thumb_path, const char *thumb_key, Eina_Bool success) +{ + Widget_Data *wd = data; + + edje_object_signal_emit(wd->children.frm, EDJE_SIGNAL_PULSE_STOP, "elm"); + wd->is_generating = EINA_FALSE; + + if (success) + { + _finished_thumb(wd, id, thumb_path, thumb_key); + return; + } + + ERR("could not generate thumbnail for %s", file); + edje_object_signal_emit(wd->children.frm, EDJE_SIGNAL_GENERATE_ERROR, "elm"); + evas_object_smart_callback_call(wd->self, "generate,error", NULL); +} + +static void +_thumb_apply(Widget_Data *wd) +{ + ethumb_client_file_set(_elm_ethumb_client, wd->file, wd->key); + if (ethumb_client_thumb_exists(_elm_ethumb_client)) + { + const char *thumb_path, *thumb_key; + ethumb_client_thumb_path_get(_elm_ethumb_client, &thumb_path, + &thumb_key); + _finished_thumb(wd, 0, thumb_path, thumb_key); + return; + } + else if (ethumb_client_generate(_elm_ethumb_client, _finished_thumb_cb, wd, + NULL) != -1) + { + edje_object_signal_emit(wd->children.frm, EDJE_SIGNAL_PULSE_START, + "elm"); + edje_object_signal_emit(wd->children.frm, EDJE_SIGNAL_GENERATE_START, + "elm"); + evas_object_smart_callback_call(wd->self, "generate,start", NULL); + } + else + { + edje_object_signal_emit(wd->children.frm, EDJE_SIGNAL_GENERATE_ERROR, + "elm"); + evas_object_smart_callback_call(wd->self, "generate,error", NULL); + } + wd->is_generating = EINA_FALSE; +} + +static int +_thumb_apply_cb(void *data, int type, void *ev) +{ + _thumb_apply(data); + return ECORE_CALLBACK_RENEW; +} + +static void +_thumb_show(Widget_Data *wd) +{ + evas_object_show(wd->children.frm); + + if (elm_thumb_ethumb_client_connected()) + { + _thumb_apply(wd); + return; + } + + if (!wd->eeh) + wd->eeh = ecore_event_handler_add(ELM_ECORE_EVENT_ETHUMB_CONNECT, + _thumb_apply_cb, wd); +} + +static void +_thumb_show_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + _thumb_show(data); +} + +static void +_cancel_cb(void *data, Eina_Bool success) +{ + Widget_Data *wd = data; + + if (success) + { + wd->is_generating = EINA_FALSE; + edje_object_signal_emit(wd->children.frm, EDJE_SIGNAL_GENERATE_STOP, + "elm"); + evas_object_smart_callback_call(wd->self, "generate,stop", NULL); + } +} + +static void +_thumb_hide_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Widget_Data *wd = data; + + evas_object_hide(wd->children.frm); + + if (wd->is_generating) + ethumb_client_generate_cancel(_elm_ethumb_client, wd->id, _cancel_cb, wd, NULL); + else if (wd->eeh) + { + ecore_event_handler_del(wd->eeh); + wd->eeh = NULL; + } +} + +static Eina_Bool +_thumb_calc_aspect(Widget_Data *wd, int tw, int th, int *ix, int *iy, int *iw, int *ih) +{ + if (!wd->children.view) + return EINA_FALSE; + + *ih = th; + *iw = tw; + *ix = *iy = 0; + + if (wd->keep_aspect) + { + float a, aspect; + Evas_Coord w, h; + + evas_object_image_size_get(wd->children.view, &w, &h); + + a = (h <= 0) ? 999999 : w / (float)h; + aspect = (th <= 0) ? 999999 : tw / (float)th; + + if ((aspect < a) && (tw > 0 || th <= 0)) + *ih = tw / a; + else if ((aspect > a) && (th > 0 || tw <= 0)) + *iw = th * a; + + *ix = - wd->children.align.x * (*iw - tw); + *iy = - wd->children.align.y * (*ih - th); + } + + return EINA_TRUE; +} + +static void +_thumb_geometry_set(Widget_Data *wd) +{ + Evas_Coord x, y, w, h, ix, iy, cw, ch; + + evas_object_geometry_get(wd->self, &x, &y, &w, &h); + + if (_thumb_calc_aspect(wd, w, h, &ix, &iy, &cw, &ch)) + { + evas_object_resize(wd->children.frm, cw, ch); + evas_object_move(wd->children.frm, x + ix, y + iy); + if (wd->is_video) + evas_object_resize(wd->children.view, cw, ch); + else + evas_object_image_fill_set(wd->children.view, 0, 0, cw, ch); + evas_object_size_hint_min_set(wd->children.view, cw, ch); + evas_object_size_hint_max_set(wd->children.view, cw, ch); + } + else + { + evas_object_move(wd->children.frm, x, y); + evas_object_resize(wd->children.frm, w, h); + } +} + +static void +_thumb_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + _thumb_geometry_set(data); +} + +static void +_thumb_resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + _thumb_geometry_set(data); +} +#endif + +#ifdef ELM_ETHUMB +static Eina_Bool _elm_need_ethumb = 0; + +static void _on_die_cb(void *, Ethumb_Client *); + +static void +_connect_cb(void *data, Ethumb_Client *c, Eina_Bool success) +{ + if (success) + { + ethumb_client_on_server_die_callback_set(c, _on_die_cb, NULL, NULL); + _elm_ethumb_connected = EINA_TRUE; + ecore_event_add(ELM_ECORE_EVENT_ETHUMB_CONNECT, NULL, NULL, NULL); + } + else + _elm_ethumb_client = NULL; +} + +static void +_on_die_cb(void *data, Ethumb_Client *c) +{ + ethumb_client_disconnect(_elm_ethumb_client); + _elm_ethumb_client = NULL; + _elm_ethumb_connected = EINA_FALSE; + _elm_ethumb_client = ethumb_client_connect(_connect_cb, NULL, NULL); +} +#endif + +void +_elm_unneed_ethumb(void) +{ +#ifdef ELM_ETHUMB + if (_elm_need_ethumb) + { + _elm_need_ethumb = 0; + ethumb_client_disconnect(_elm_ethumb_client); + _elm_ethumb_client = NULL; + ethumb_client_shutdown(); + ELM_ECORE_EVENT_ETHUMB_CONNECT = 0; + } +#endif +} + +/** + * This must be called before any other function that handle with + * elm_thumb objects or ethumb_client instances. + * + * @ingroup Thumb + */ +EAPI void +elm_need_ethumb(void) +{ +#ifdef ELM_ETHUMB + if (_elm_need_ethumb) + return; + ELM_ECORE_EVENT_ETHUMB_CONNECT = ecore_event_type_new(); + _elm_need_ethumb = 1; + ethumb_client_init(); + _elm_ethumb_client = ethumb_client_connect(_connect_cb, NULL, NULL); +#endif +} + +/** + * Add a new thumb object to the parent. + * + * @param parent The parent object. + * @return The new object or NULL if it cannot be created. + * + * @see elm_thumb_file_set() + * @see elm_thumb_ethumb_client_get() + * @see elm_thumb_keep_aspect_set() + * @see elm_thumb_align_set() + * @see elm_thumb_align_get() + * + * @ingroup Thumb + */ +EAPI Evas_Object * +elm_thumb_add(Evas_Object *parent) +{ + Evas *evas; + Widget_Data *wd; + Evas_Object *obj; + Evas_Coord minw, minh; + + wd = ELM_NEW(Widget_Data); + evas = evas_object_evas_get(parent); + obj = elm_widget_add(evas); + ELM_SET_WIDTYPE(widtype, "thumb"); + elm_widget_type_set(obj, "thumb"); + elm_widget_sub_object_add(parent, obj); + elm_widget_data_set(obj, wd); + elm_widget_del_hook_set(obj, _del_hook); + elm_widget_theme_hook_set(obj, _theme_hook); + + wd->children.frm = edje_object_add(evas); + _elm_theme_set(wd->children.frm, "thumb", "base", "default"); + elm_widget_sub_object_add(obj, wd->children.frm); + + edje_object_size_min_calc(obj, &minw, &minh); + evas_object_size_hint_min_set(obj, minw, minh); + + wd->self = obj; + wd->children.view = NULL; + wd->file = NULL; + wd->key = NULL; + wd->eeh = NULL; + wd->children.align.x = 0.5; + wd->children.align.y = 0.5; + wd->on_hold = EINA_FALSE; + wd->is_video = EINA_FALSE; + wd->is_generating = EINA_FALSE; + wd->keep_aspect = EINA_FALSE; + +#ifdef HAVE_ELEMENTARY_ETHUMB + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN, + _mouse_down_cb, wd); + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP, + _mouse_up_cb, wd); + evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, + _thumb_show_cb, wd); + evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, + _thumb_hide_cb, wd); + evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, + _thumb_resize_cb, wd); + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, + _thumb_move_cb, wd); +#endif + + return obj; +} + +/** + * Set the file that will be used as thumbnail. + * + * The file can be an image or a video (in that case, acceptable extensions are: + * avi, mp4, ogv, mov, mpg and wmv). To start the video animation, use the + * function elm_thumb_animate(). + * + * @param obj The thumb object. + * @param file The path to file that will be used as thumb. + * @param key The key used in case of an EET file. + * + * @see elm_thumb_file_get() + * @see elm_thumb_animate() + * + * @ingroup Thumb + */ +EAPI void +elm_thumb_file_set(Evas_Object *obj, const char *file, const char *key) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Eina_Bool file_replaced, key_replaced; + Widget_Data *wd = elm_widget_data_get(obj); + + file_replaced = eina_stringshare_replace(&(wd->file), file); + key_replaced = eina_stringshare_replace(&(wd->key), key); + + if (file_replaced) + { + int prefix_size; + const char **ext, *ptr; + static const char *extensions[] = { ".avi", ".mp4", ".ogv", ".mov", + ".mpg", ".wmv", NULL }; + + prefix_size = eina_stringshare_strlen(wd->file) - 4; + if (prefix_size >= 0) + { + ptr = wd->file + prefix_size; + wd->is_video = EINA_FALSE; + for (ext = extensions; *ext; ext++) + if (!strcasecmp(ptr, *ext)) + { + wd->is_video = EINA_TRUE; + break; + } + } + } + +#ifdef HAVE_ELEMENTARY_ETHUMB + if ((file_replaced || key_replaced) && evas_object_visible_get(obj)) + _thumb_show(wd); +#endif +} + +/** + * Get the image or video path and key used to generate the thumbnail. + * + * @param obj The thumb object. + * @param file Pointer to filename. + * @param key Pointer to key. + * + * @see elm_thumb_file_set() + * @see elm_thumb_animate() + * + * @ingroup Thumb + */ +EAPI void +elm_thumb_file_get(Evas_Object *obj, const char **file, const char **key) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (file) + *file = wd->file; + if (key) + *key = wd->key; +} + +/** + * Start animation if the thumbnail is an animated video. + * + * @param obj The thumb object. + * @param setting The animation setting. + * + * @see elm_thumb_file_set() + * + * @ingroup Thumb + */ +EAPI void +elm_thumb_animate(Evas_Object *obj, Elm_Thumb_Animation_Setting setting) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (setting == ELM_THUMB_ANIMATION_LOOP) + edje_object_signal_emit(wd->children.view, "animate_loop", ""); + else if (setting == ELM_THUMB_ANIMATION_START) + edje_object_signal_emit(wd->children.view, "animate", ""); + else if (setting == ELM_THUMB_ANIMATION_STOP) + edje_object_signal_emit(wd->children.view, "animate_stop", ""); +} + +/** + * Set whether the thumbnail exhibition should keep the image or video aspect. + * + * For positioning the image/video within the object use the function + * elm_thumb_align_set(). + * + * @param obj The thumb object. + * @param setting Whether keep or not the aspect. + * + * @see elm_thumb_file_set() + * @see elm_thumb_align_set() + * + * @ingroup Thumb + */ +EAPI void +elm_thumb_keep_aspect_set(Evas_Object *obj, Eina_Bool setting) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + wd->keep_aspect = setting; +} + +/** + * Set image/video's alignment within the thumbnail. + * + * @param obj The thumb object. + * @param x_align The x alignment (0 <= x <= 1). + * @param y_align The y alignment (0 <= y <= 1). + * + * @see elm_thumb_keep_aspect_set() + * @see elm_thumb_align_get() + * + * @ingroup Thumb + */ +EAPI void +elm_thumb_align_set(Evas_Object *obj, float x_align, float y_align) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + + if (x_align > 1.0) + x_align = 1.0; + else if (x_align < 0.0) + x_align = 0.0; + wd->children.align.x = x_align; + + if (y_align > 1.0) + y_align = 1.0; + else if (y_align < 0.0) + y_align = 0.0; + wd->children.align.y = y_align; + + _thumb_geometry_set(wd); +} + +/** + * Get the alignenment set for the thumb object. + * + * @param obj The thumb object. + * @param x Pointer to x alignenment. + * @param y Pointer to y alignenment. + * + * @see elm_thumb_align_set() + * + * @ingroup Thumb + */ +EAPI void +elm_thumb_align_get(Evas_Object *obj, float *x, float *y) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (x) *x = wd->children.align.x; + if (y) *y = wd->children.align.y; +} + +/** + * Get the ethumb_client handle so custom configuration can be made. + * This must be called before the objects are created to be sure no object is + * visible and no generation started. + * + * @return Ethumb_Client instance or NULL. + * + * Example of usage: + * + * @code + * #include + * #ifndef ELM_LIB_QUICKLAUNCH + * EAPI int + * elm_main(int argc, char **argv) + * { + * Ethumb_Client *client; + * + * elm_need_ethumb(); + * + * // ... your code + * + * client = elm_thumb_ethumb_client_get(); + * if (!client) + * { + * ERR("could not get ethumb_client"); + * return 1; + * } + * ethumb_client_size_set(client, 100, 100); + * ethumb_client_crop_align_set(client, 0.5, 0.5); + * // ... your code + * + * // Create elm_thumb objects here + * + * elm_run(); + * elm_shutdown(); + * return 0; + * } + * #endif + * ELM_MAIN() + * @endcode + * + * @ingroup Thumb + */ +#ifdef ELM_ETHUMB +EAPI Ethumb_Client * +elm_thumb_ethumb_client_get(void) +{ + return _elm_ethumb_client; +} +#else +EAPI void * +elm_thumb_ethumb_client_get(void) +{ + return NULL; +} +#endif + +/** + * Get the ethumb_client connection state. + * + * @return EINA_TRUE if the client is connected to the server or + * EINA_FALSE otherwise. + */ +EAPI Eina_Bool +elm_thumb_ethumb_client_connected(void) +{ + return _elm_ethumb_connected; +} -- 2.7.4