From b44a686b5364146e0e711f4d13ac635c2e018902 Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Mon, 11 Oct 2010 01:10:27 +0000 Subject: [PATCH] one more day of work on ephoto, still not complete. flow browser (why that name?!) is back, with the my traditional combination of 255,0 in rgb colored buttons in edje. tomorrow will work on slideshow and make it work. NOTE: ProFUSION team will work on a solution to have elm_toolbar + elm_menu to be good and provide what we have in eve/enjoy in a more generic way without thousand lines of macros in EDC. The goal is to have configurable implementation that would provide some UI on desktop and another on embedded, also showing buttons as we have space, and hidding them with an automatic "more" entry if there is no space for all items. That should improve eve, enjoy, ephoto and possibly others. SVN revision: 53250 --- data/themes/default/ephoto.edc | 501 +++++++++++++++++++++++++-------- src/bin/ephoto.h | 7 +- src/bin/ephoto_flow_browser.c | 410 ++++++++++++++++++++++++++- src/bin/ephoto_main.c | 113 ++++++-- src/bin/ephoto_thumb_browser.c | 46 ++- 5 files changed, 919 insertions(+), 158 deletions(-) diff --git a/data/themes/default/ephoto.edc b/data/themes/default/ephoto.edc index da08ce0..62b369c 100644 --- a/data/themes/default/ephoto.edc +++ b/data/themes/default/ephoto.edc @@ -725,6 +725,78 @@ collections type: SWALLOW; description { state: "default" 0.0; } + description { state: "hidden" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + } + + parts { + part { name: "ephoto.swallow.flow_browser"; + type: SWALLOW; + description { state: "default" 0.0; + } + description { state: "hidden" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + } + + parts { + part { name: "ephoto.swallow.slideshow"; + type: SWALLOW; + description { state: "default" 0.0; + } + description { state: "hidden" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + } + + programs { + program { + signal: "thumb_browser,show"; + source: "ephoto"; + action: STATE_SET "hidden" 0.0; + target: "ephoto.swallow.flow_browser"; + target: "ephoto.swallow.slideshow"; + after: "thumb_browser.show2"; + } + program { + name: "thumb_browser.show2"; + action: STATE_SET "default" 0.0; + target: "ephoto.swallow.thumb_browser"; + } + + program { + signal: "flow_browser,show"; + source: "ephoto"; + action: STATE_SET "hidden" 0.0; + target: "ephoto.swallow.thumb_browser"; + target: "ephoto.swallow.slideshow"; + after: "flow_browser.show2"; + } + program { + name: "flow_browser.show2"; + action: STATE_SET "default" 0.0; + target: "ephoto.swallow.flow_browser"; + } + + program { + signal: "slideshow,show"; + source: "ephoto"; + action: STATE_SET "hidden" 0.0; + target: "ephoto.swallow.thumb_browser"; + target: "ephoto.swallow.flow_browser"; + after: "slideshow.show2"; + } + program { + name: "slideshow.show2"; + action: STATE_SET "default" 0.0; + target: "ephoto.swallow.slideshow"; } } } @@ -794,7 +866,7 @@ collections } } - part { name: "ephoto.thumb.swallow"; + part { name: "ephoto.swallow.thumb"; type: SWALLOW; description { state: "default" 0.0; rel1 { to: "ephoto.location"; @@ -915,139 +987,322 @@ collections } } - group - { - name: "ephoto/flow/layout"; + group { name: "ephoto/flow/layout"; parts { - part { - name: "ephoto.flow.swallow"; - type: SWALLOW; + part { name: "back"; + type: RECT; description { state: "default" 0.0; - rel2.to: "ephoto.toolbar.swallow"; - rel2.relative: 1 0; - map { - on: 0; + color: 255 255 0 255; + rel1.offset: 10 5; + rel2 { relative: 0.0 0.0; + offset: 30 24; } } - description { - state: "rotate_0" 0.0; - inherit: "default" 0.0; - map { - on: 1; - rotation { - z: 0; - } - } - } - description { - state: "rotate_90" 0.0; - inherit: "default" 0.0; - map { - on: 1; - rotation { - z: 90; - } - } - } - description { - state: "rotate_180" 0.0; - inherit: "default" 0.0; - map { - on: 1; - rotation { - z: 180; - } - } - } - description { - state: "rotate_270" 0.0; - inherit: "default" 0.0; - map { - on: 1; - rotation { - z: 270; - } - } + } + programs { + program { + signal: "mouse,clicked,*"; + source: "back"; + action: SIGNAL_EMIT "back" "ephoto"; } } - part { - name: "ephoto.toolbar.swallow"; - type: SWALLOW; - description { - color: 0 255 0 255; - state: "default" 0.0; - rel1.relative: 0 1; - rel1.offset: 0 -63; - } - } - } - programs { - program { - name: "go_rotate_0"; - signal: "ef,state,rotate,0"; - source: "ef"; - action: STATE_SET "rotate_0" 0.0; - transition: SINUSOIDAL 0.2; - target: "ephoto.flow.swallow"; - } - program { - name: "go_rotate_90"; - signal: "ef,state,rotate,90"; - source: "ef"; - action: STATE_SET "rotate_90" 0.0; - transition: SINUSOIDAL 0.2; - target: "ephoto.flow.swallow"; - } - program { - name: "go_rotate_180"; - signal: "ef,state,rotate,180"; - source: "ef"; - action: STATE_SET "rotate_180" 0.0; - transition: SINUSOIDAL 0.2; - target: "ephoto.flow.swallow"; - } - program { - name: "go_rotate_270"; - signal: "ef,state,rotate,270"; - source: "ef"; - action: STATE_SET "rotate_270" 0.0; - transition: SINUSOIDAL 0.2; - target: "ephoto.flow.swallow"; - } - } - } - - group { name: "/ephoto/directory/no-preview"; - images { - set { name: "directory"; - image { - image: "directory-128.png" COMP; - size: 1 1 128 128; - } - image { - image: "directory-256.png" COMP; - size: 129 129 256 256; - } - image { - image: "directory-512.png" COMP; - size: 257 257 512 512; - } - } - } - parts { - part { name: "img"; - type: IMAGE; + part { name: "ephoto.text.title"; + type: TEXT; + effect: SOFT_SHADOW; mouse_events: 0; - description { - state: "default" 0.0; - aspect_preference: BOTH; - aspect: 1.0 1.0; - image.normal: "directory"; + description { state: "default" 0.0; + rel1 { to_x: "back"; + relative: 1.0 0.0; + offset: 5 5; + } + rel2 { relative: 1.0 0.0; + offset: -11 24; + } + text { + font: "Sans:style=Bold"; + size: 12; + } + } + } + + part { name: "ephoto.swallow.flow"; + type: SWALLOW; + description { state: "default" 0.0; + rel1 { to_y: "ephoto.text.title"; + relative: 0.0 1.0; + offset: 0 10; + } + rel2 { to_y: "iconbar.bg"; + relative: 1.0 0.0; + } + } + description { state: "rotate_0" 0.0; + inherit: "default" 0.0; + map { + on: 1; + rotation.z: 0; + } + } + description { state: "rotate_90" 0.0; + inherit: "default" 0.0; + map { + on: 1; + rotation.z: 90; + } + } + description { state: "rotate_180" 0.0; + inherit: "default" 0.0; + map { + on: 1; + rotation.z: 180; + } + } + description { state: "rotate_270" 0.0; + inherit: "default" 0.0; + map { + on: 1; + rotation.z: 270; + } + } + } + programs { + program { + signal: "state,rotate,0"; + source: "ephoto"; + action: STATE_SET "rotate_0" 0.0; + transition: SINUSOIDAL 0.2; + target: "ephoto.swallow.flow"; + } + program { + signal: "state,rotate,90"; + source: "ephoto"; + action: STATE_SET "rotate_90" 0.0; + transition: SINUSOIDAL 0.2; + target: "ephoto.swallow.flow"; + } + program { + signal: "state,rotate,180"; + source: "ephoto"; + action: STATE_SET "rotate_180" 0.0; + transition: SINUSOIDAL 0.2; + target: "ephoto.swallow.flow"; + } + program { + signal: "state,rotate,270"; + source: "ephoto"; + action: STATE_SET "rotate_270" 0.0; + transition: SINUSOIDAL 0.2; + target: "ephoto.swallow.flow"; + } + } + + part { name: "iconbar.bg"; + type: RECT; + description { state: "default" 0.0; + rel1 { relative: 0.0 1.0; + offset: 0 -64; + } + } + } + + part { name: "zoom_in_area"; + type: RECT; + description { state: "default" 0.0; + color: 0 0 0 0; + rel1.to: "zoom_in"; + rel2.to: "zoom_in"; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + visible: 0; /* no events */ + } + } + part { name: "zoom_in"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + color: 255 0 0 255; + rel1 { to_y: "iconbar.bg"; + relative: 0.0 0.0; + } + rel2.relative: 0.2 1.0; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + color: 0 0 0 255; + } + } + programs { + program { + signal: "mouse,clicked,*"; + source: "zoom_in_area"; + action: SIGNAL_EMIT "zoom_in,clicked" "ephoto"; + } + program { + signal: "zoom_in,disable"; + source: "ephoto"; + action: STATE_SET "disabled" 0.0; + target: "zoom_in"; + target: "zoom_in_area"; + } + program { + signal: "zoom_in,enable"; + source: "ephoto"; + action: STATE_SET "default" 0.0; + target: "zoom_in"; + target: "zoom_in_area"; + } + } + + part { name: "zoom_out_area"; + type: RECT; + description { state: "default" 0.0; + color: 0 0 0 0; + rel1.to: "zoom_out"; + rel2.to: "zoom_out"; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + visible: 0; /* no events */ + } + } + part { name: "zoom_out"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + color: 0 255 0 255; + rel1 { to_y: "iconbar.bg"; + relative: 0.2 0.0; + } + rel2.relative: 0.4 1.0; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + color: 0 0 0 255; + } + } + programs { + program { + signal: "mouse,clicked,*"; + source: "zoom_out_area"; + action: SIGNAL_EMIT "zoom_out,clicked" "ephoto"; + } + program { + signal: "zoom_out,disable"; + source: "ephoto"; + action: STATE_SET "disabled" 0.0; + target: "zoom_out"; + target: "zoom_out_area"; + } + program { + signal: "zoom_out,enable"; + source: "ephoto"; + action: STATE_SET "default" 0.0; + target: "zoom_out"; + target: "zoom_out_area"; + } + } + + part { name: "prev_area"; + type: RECT; + description { state: "default" 0.0; + color: 0 0 0 0; + rel1.to: "prev"; + rel2.to: "prev"; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + visible: 0; /* no events */ + } + } + part { name: "prev"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + color: 0 0 255 255; + rel1 { to_y: "iconbar.bg"; + relative: 0.4 0.0; + } + rel2.relative: 0.6 1.0; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + color: 0 0 0 255; + } + } + programs { + program { + signal: "mouse,clicked,*"; + source: "prev_area"; + action: SIGNAL_EMIT "prev,clicked" "ephoto"; + } + program { + signal: "prev,disable"; + source: "ephoto"; + action: STATE_SET "disabled" 0.0; + target: "prev"; + target: "prev_area"; + } + program { + signal: "prev,enable"; + source: "ephoto"; + action: STATE_SET "default" 0.0; + target: "prev"; + target: "prev_area"; + } + } + + part { name: "next_area"; + type: RECT; + description { state: "default" 0.0; + color: 0 0 0 0; + rel1.to: "next"; + rel2.to: "next"; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + visible: 0; /* no events */ + } + } + part { name: "next"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + color: 255 0 255 255; + rel1 { to_y: "iconbar.bg"; + relative: 0.6 0.0; + } + rel2.relative: 0.8 1.0; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + color: 0 0 0 255; + } + } + programs { + program { + signal: "mouse,clicked,*"; + source: "next_area"; + action: SIGNAL_EMIT "next,clicked" "ephoto"; + } + program { + signal: "next,disable"; + source: "ephoto"; + action: STATE_SET "disabled" 0.0; + target: "next"; + target: "next_area"; + } + program { + signal: "next,enable"; + source: "ephoto"; + action: STATE_SET "default" 0.0; + target: "next"; + target: "next_area"; } } } } -} +} diff --git a/src/bin/ephoto.h b/src/bin/ephoto.h index b6821cc..cac0973 100644 --- a/src/bin/ephoto.h +++ b/src/bin/ephoto.h @@ -33,6 +33,7 @@ typedef enum _Ephoto_Orient Ephoto_Orient; /*Main Functions*/ Evas_Object *ephoto_window_add(const char *path); +void ephoto_title_set(Ephoto *ephoto, const char *title); void ephoto_thumb_size_set(Ephoto *ephoto, int size); Evas_Object *ephoto_thumb_add(Ephoto *ephoto, Evas_Object *parent, const char *path); void ephoto_thumb_path_set(Evas_Object *o, const char *path); @@ -48,7 +49,9 @@ void ephoto_show_preferences(Ephoto *em); /*Ephoto Flow Browser*/ Evas_Object *ephoto_flow_browser_add(Ephoto *ephoto, Evas_Object *parent); -void ephoto_flow_browser_image_set(Evas_Object *obj, const char *current_image); +void ephoto_flow_browser_path_set(Evas_Object *obj, const char *image); +void ephoto_flow_browser_entry_set(Evas_Object *obj, Ephoto_Entry *entry); + /* smart callbacks called: * "back" - the user requested to delete the flow browser, typically called when go_back button is pressed or Escape key is typed. */ @@ -66,6 +69,7 @@ Evas_Object *ephoto_directory_thumb_add(Evas_Object *parent, Ephoto_Entry *e); /*Ephoto Thumb Browser*/ Evas_Object *ephoto_thumb_browser_add(Ephoto *ephoto, Evas_Object *parent); void ephoto_thumb_browser_directory_set(Evas_Object *obj, const char *path); +void ephoto_thumb_browser_path_pending_set(Evas_Object *obj, const char *path, void (*cb)(void *data, Ephoto_Entry *entry), const void *data); /* smart callbacks called: * "selected" - an item in the thumb browser is selected. The selected file is passed as event_info argument. @@ -116,6 +120,7 @@ struct _Ephoto Evas_Object *win; Evas_Object *bg; Evas_Object *layout; + Evas_Object *edje; Evas_Object *thumb_browser; Evas_Object *flow_browser; diff --git a/src/bin/ephoto_flow_browser.c b/src/bin/ephoto_flow_browser.c index 83b0823..44d4a9d 100644 --- a/src/bin/ephoto_flow_browser.c +++ b/src/bin/ephoto_flow_browser.c @@ -1,30 +1,432 @@ #include "ephoto.h" #ifdef HAVE_LIBEXIF - #include +#include #endif +#define ZOOM_MIN 0.1 +#define ZOOM_MAX 10.0 +#define ZOOM_STEP 0.2 + +typedef struct _Ephoto_Flow_Browser Ephoto_Flow_Browser; +typedef struct _Ephoto_Viewer Ephoto_Viewer; + +struct _Ephoto_Flow_Browser +{ + Ephoto *ephoto; + Evas_Object *layout; + Evas_Object *edje; + Evas_Object *viewer; + const char *path; + Ephoto_Entry *entry; + double zoom; +}; + +struct _Ephoto_Viewer +{ + Evas_Object *photocam; + Evas_Object *scroller; + Evas_Object *image; +}; + +static void _zoom_set(Ephoto_Flow_Browser *fb, double zoom); + +static Eina_Bool +_path_is_jpeg(const char *path_stringshared) +{ + size_t len = eina_stringshare_strlen(path_stringshared); + const char *ext; + + if (len < sizeof(".jpg")) return EINA_FALSE; + ext = path_stringshared + len - (sizeof(".jpg") - 1); + if (strcasecmp(ext, ".jpg") == 0) return EINA_TRUE; + + if (len < sizeof(".jpeg")) return EINA_FALSE; + ext = path_stringshared + len - (sizeof(".jpeg") - 1); + if (strcasecmp(ext, ".jpeg") == 0) return EINA_TRUE; + + return EINA_FALSE; +} + +static void +_viewer_del(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Ephoto_Viewer *v = data; + free(v); +} + +static Evas_Object * +_viewer_add(Evas_Object *parent, const char *path) +{ + Ephoto_Viewer *v = calloc(1, sizeof(Ephoto_Viewer)); + Evas_Object *obj; + int err; + + EINA_SAFETY_ON_NULL_RETURN_VAL(v, NULL); + if (_path_is_jpeg(path)) + { + obj = v->photocam = elm_photocam_add(parent); + EINA_SAFETY_ON_NULL_GOTO(obj, error); + err = elm_photocam_file_set(obj, path); + if (err != EVAS_LOAD_ERROR_NONE) goto load_error; + } + else + { + Evas_Coord w, h; + obj = v->scroller = elm_scroller_add(parent); + EINA_SAFETY_ON_NULL_GOTO(obj, error); + v->image = evas_object_image_filled_add(evas_object_evas_get(parent)); + evas_object_image_file_set(v->image, path, NULL); + err = evas_object_image_load_error_get(v->image); + if (err != EVAS_LOAD_ERROR_NONE) goto load_error; + evas_object_image_size_get(v->image, &w, &h); + evas_object_size_hint_align_set(v->image, 0.5, 0.5); + evas_object_size_hint_min_set(v->image, w, h); + evas_object_size_hint_max_set(v->image, w, h); + evas_object_resize(v->image, w, h); + evas_object_show(v->image); + elm_scroller_content_set(obj, v->image); + } + + evas_object_size_hint_weight_set(obj, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(obj, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_data_set(obj, "viewer", v); + evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _viewer_del, v); + return obj; + + load_error: + ERR("could not load image '%s': %s", path, evas_load_error_str(err)); + evas_object_del(obj); + error: + free(v); + return NULL; +} + +static void +_viewer_zoom_set(Evas_Object *obj, float zoom) +{ + Ephoto_Viewer *v = evas_object_data_get(obj, "viewer"); + EINA_SAFETY_ON_NULL_RETURN(v); + + if (v->photocam) elm_photocam_zoom_set(v->photocam, 1.0 / zoom); + else + { + Evas_Coord w, h; + evas_object_image_size_get(v->image, &w, &h); + w *= zoom; + h *= zoom; + evas_object_size_hint_min_set(v->image, w, h); + evas_object_size_hint_max_set(v->image, w, h); + } +} + +static void +_mouse_wheel(void *data, Evas *e, Evas_Object *o, void *event_info) +{ + Ephoto_Flow_Browser *fb = data; + Evas_Event_Mouse_Wheel *ev = event_info; + if (!evas_key_modifier_is_set(ev->modifiers, "Control")) return; + + if (ev->z > 0) _zoom_set(fb, fb->zoom + ZOOM_STEP); + else _zoom_set(fb, fb->zoom - ZOOM_STEP); +} + +static Ephoto_Entry * +_find_first_entry(Ephoto_Flow_Browser *fb) +{ + const Eina_List *l; + Ephoto_Entry *entry; + EINA_SAFETY_ON_NULL_RETURN_VAL(fb->ephoto, NULL); + + EINA_LIST_FOREACH(fb->ephoto->entries, l, entry) + if (!entry->is_dir) return entry; + return NULL; +} + +static Ephoto_Entry * +_find_last_entry(Ephoto_Flow_Browser *fb) +{ + const Eina_List *l; + Ephoto_Entry *entry; + EINA_SAFETY_ON_NULL_RETURN_VAL(fb->ephoto, NULL); + + EINA_LIST_REVERSE_FOREACH(fb->ephoto->entries, l, entry) + if (!entry->is_dir) return entry; + return NULL; +} + +static void +_ephoto_flow_browser_toolbar_eval(Ephoto_Flow_Browser *fb) +{ + if (!fb->entry) + { + edje_object_signal_emit(fb->edje, "slideshow,disable", "ephoto"); + edje_object_signal_emit(fb->edje, "prev,disable", "ephoto"); + edje_object_signal_emit(fb->edje, "next,disable", "ephoto"); + } + else + { + edje_object_signal_emit(fb->edje, "slideshow,enable", "ephoto"); + + if (fb->entry == _find_first_entry(fb)) + edje_object_signal_emit(fb->edje, "prev,disable", "ephoto"); + else + edje_object_signal_emit(fb->edje, "prev,enable", "ephoto"); + + if (fb->entry == _find_last_entry(fb)) + edje_object_signal_emit(fb->edje, "next,disable", "ephoto"); + else + edje_object_signal_emit(fb->edje, "next,enable", "ephoto"); + } +} + +static void +_ephoto_flow_browser_recalc(Ephoto_Flow_Browser *fb) +{ + if (fb->viewer) + { + evas_object_del(fb->viewer); + fb->viewer = NULL; + } + + if (fb->path) + { + const char *bname = ecore_file_file_get(fb->path); + fb->viewer = _viewer_add(fb->layout, fb->path); + elm_layout_content_set(fb->layout, "ephoto.swallow.flow", fb->viewer); + evas_object_event_callback_add + (fb->viewer, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel, fb); + edje_object_part_text_set(fb->edje, "ephoto.text.title", bname); + ephoto_title_set(fb->ephoto, bname); + } + + _ephoto_flow_browser_toolbar_eval(fb); +} + +static void +_zoom_set(Ephoto_Flow_Browser *fb, double zoom) +{ + if (zoom > ZOOM_MAX) zoom = ZOOM_MAX; + else if (zoom < ZOOM_MIN) zoom = ZOOM_MIN; + + DBG("zoom %f", zoom); + _viewer_zoom_set(fb->viewer, zoom); + fb->zoom = zoom; + + if (zoom <= ZOOM_MIN) + edje_object_signal_emit(fb->edje, "zoom_out,disable", "ephoto"); + else + edje_object_signal_emit(fb->edje, "zoom_out,enable", "ephoto"); + + if (zoom >= ZOOM_MAX) + edje_object_signal_emit(fb->edje, "zoom_in,disable", "ephoto"); + else + edje_object_signal_emit(fb->edje, "zoom_in,enable", "ephoto"); +} + +static void +_zoom_in(void *data, Evas_Object *o, const char *emission, const char *source) +{ + Ephoto_Flow_Browser *fb = data; + _zoom_set(fb, fb->zoom + ZOOM_STEP); +} + +static void +_zoom_out(void *data, Evas_Object *o, const char *emission, const char *source) +{ + Ephoto_Flow_Browser *fb = data; + _zoom_set(fb, fb->zoom - ZOOM_STEP); +} + +static void +_next_entry(Ephoto_Flow_Browser *fb) +{ + Elm_Gengrid_Item *it; + Ephoto_Entry *entry; + EINA_SAFETY_ON_NULL_RETURN(fb->entry); + EINA_SAFETY_ON_NULL_RETURN(fb->entry->item); + + it = fb->entry->item; + while ((it = elm_gengrid_item_next_get(it))) + { + entry = elm_gengrid_item_data_get(it); + if (!entry->is_dir) break; + } + if (!it) return; + DBG("next is '%s'", entry->path); + ephoto_flow_browser_entry_set(fb->layout, entry); +} + +static void +_prev_entry(Ephoto_Flow_Browser *fb) +{ + Elm_Gengrid_Item *it; + Ephoto_Entry *entry; + EINA_SAFETY_ON_NULL_RETURN(fb->entry); + EINA_SAFETY_ON_NULL_RETURN(fb->entry->item); + + it = fb->entry->item; + while ((it = elm_gengrid_item_prev_get(it))) + { + entry = elm_gengrid_item_data_get(it); + if (!entry->is_dir) break; + } + if (!it) return; + DBG("prev is '%s'", entry->path); + ephoto_flow_browser_entry_set(fb->layout, entry); +} + +static void +_first_entry(Ephoto_Flow_Browser *fb) +{ + Ephoto_Entry *entry = _find_first_entry(fb); + if (!entry) return; + DBG("first is '%s'", entry->path); + ephoto_flow_browser_entry_set(fb->layout, entry); +} + +static void +_last_entry(Ephoto_Flow_Browser *fb) +{ + Ephoto_Entry *entry = _find_last_entry(fb); + if (!entry) return; + DBG("last is '%s'", entry->path); + ephoto_flow_browser_entry_set(fb->layout, entry); +} + +static void +_next_button(void *data, Evas_Object *o, const char *emission, const char *source) +{ + Ephoto_Flow_Browser *fb = data; + _next_entry(fb); +} + +static void +_prev_button(void *data, Evas_Object *o, const char *emission, const char *source) +{ + Ephoto_Flow_Browser *fb = data; + _prev_entry(fb); +} + +static void +_back(void *data, Evas_Object *o, const char *emission, const char *source) +{ + Ephoto_Flow_Browser *fb = data; + evas_object_smart_callback_call(fb->layout, "back", fb->entry); +} + +static void +_key_down(void *data, Evas *e, Evas_Object *o, void *event_info) +{ + Ephoto_Flow_Browser *fb = data; + Evas_Event_Key_Down *ev = event_info; + Eina_Bool ctrl = evas_key_modifier_is_set(ev->modifiers, "Control"); + const char *k = ev->keyname; + + if (ctrl) + { + if ((!strcmp(k, "plus")) || (!strcmp(k, "equal"))) + _zoom_set(fb, fb->zoom + ZOOM_STEP); + else if (!strcmp(k, "minus")) + _zoom_set(fb, fb->zoom - ZOOM_STEP); + else if (!strcmp(k, "0")) + _zoom_set(fb, 1.0); + } + + if (!strcmp(k, "Escape")) + evas_object_smart_callback_call(fb->layout, "back", fb->entry); + else if (!strcmp(k, "Left")) + _prev_entry(fb); + else if (!strcmp(k, "Right")) + _next_entry(fb); + else if (!strcmp(k, "Home")) + _first_entry(fb); + else if (!strcmp(k, "End")) + _last_entry(fb); +} + +static void +_layout_del(void *data, Evas *e, Evas_Object *o, void *event_info) +{ + Ephoto_Flow_Browser *fb = data; + eina_stringshare_del(fb->path); + free(fb); +} + Evas_Object * ephoto_flow_browser_add(Ephoto *ephoto, Evas_Object *parent) { Evas_Object *layout = elm_layout_add(parent); + Ephoto_Flow_Browser *fb; + EINA_SAFETY_ON_NULL_RETURN_VAL(layout, NULL); + fb = calloc(1, sizeof(Ephoto_Flow_Browser)); + EINA_SAFETY_ON_NULL_GOTO(fb, error); + fb->ephoto = ephoto; + fb->layout = layout; + fb->edje = elm_layout_edje_get(layout); + fb->zoom = 1.0; + evas_object_event_callback_add(layout, EVAS_CALLBACK_DEL, _layout_del, fb); + evas_object_event_callback_add + (layout, EVAS_CALLBACK_KEY_DOWN, _key_down, fb); + elm_object_focus_allow_set(layout, EINA_TRUE); + evas_object_data_set(layout, "flow_browser", fb); + + edje_object_signal_callback_add + (fb->edje, "zoom_out,clicked", "ephoto", _zoom_out, fb); + edje_object_signal_callback_add + (fb->edje, "zoom_in,clicked", "ephoto", _zoom_in, fb); + edje_object_signal_callback_add + (fb->edje, "prev,clicked", "ephoto", _prev_button, fb); + edje_object_signal_callback_add + (fb->edje, "next,clicked", "ephoto", _next_button, fb); + edje_object_signal_callback_add + (fb->edje, "back", "ephoto", _back, fb); + if (!elm_layout_file_set(layout, THEME_FILE, "ephoto/flow/layout")) { evas_object_del(layout); return NULL; } - /* TODO */ + _ephoto_flow_browser_toolbar_eval(fb); return layout; + + error: + evas_object_del(layout); + return NULL; } void -ephoto_flow_browser_image_set(Evas_Object *obj, const char *path) +ephoto_flow_browser_path_set(Evas_Object *obj, const char *path) { - /* TODO */ + Ephoto_Flow_Browser *fb = evas_object_data_get(obj, "flow_browser"); + EINA_SAFETY_ON_NULL_RETURN(fb); + + DBG("path '%s', was '%s'", path ? path : "", fb->path ? fb->path : ""); + if (!eina_stringshare_replace(&fb->path, path)) return; + fb->entry = NULL; + fb->zoom = 1.0; + _ephoto_flow_browser_recalc(fb); +} + +void +ephoto_flow_browser_entry_set(Evas_Object *obj, Ephoto_Entry *entry) +{ + Ephoto_Flow_Browser *fb = evas_object_data_get(obj, "flow_browser"); + EINA_SAFETY_ON_NULL_RETURN(fb); + + DBG("entry %p, was %p", entry, fb->entry); + fb->entry = entry; + if (!eina_stringshare_replace(&fb->path, entry->path)) + _ephoto_flow_browser_toolbar_eval(fb); + else + { + fb->zoom = 1.0; + _ephoto_flow_browser_recalc(fb); + } } diff --git a/src/bin/ephoto_main.c b/src/bin/ephoto_main.c index f2966ee..e7de99c 100644 --- a/src/bin/ephoto_main.c +++ b/src/bin/ephoto_main.c @@ -1,31 +1,38 @@ #include "ephoto.h" static void -_ephoto_flow_browser_delete(void *data, Evas_Object *obj, void *event_info) +_ephoto_thumb_browser_show(Ephoto *ephoto, Ephoto_Entry *entry) { - Ephoto *ephoto = data; - ephoto->flow_browser = NULL; - elm_layout_content_set - (ephoto->layout, "ephoto.swallow.content", ephoto->thumb_browser); + DBG("entry '%s'", entry ? entry->path : ""); + + ephoto_flow_browser_path_set(ephoto->flow_browser, NULL); + elm_object_focus(ephoto->thumb_browser); + evas_object_focus_set(ephoto->thumb_browser, EINA_TRUE); // TODO while elm_layout is broken WRT focus + edje_object_signal_emit(ephoto->edje, "thumb_browser,show", "ephoto"); ephoto->state = EPHOTO_STATE_THUMB; + + if ((entry) && (entry->item)) elm_gengrid_item_bring_in(entry->item); } static void _ephoto_flow_browser_show(Ephoto *ephoto, Ephoto_Entry *entry) { - /* remove thumb browser without deleting it */ - elm_layout_content_unset(ephoto->layout, "ephoto.swallow.content"); - - ephoto->flow_browser = ephoto_flow_browser_add(ephoto, ephoto->layout); - ephoto_flow_browser_image_set(ephoto->flow_browser, entry->path); - elm_layout_content_set - (ephoto->layout, "ephoto.swallow.content", ephoto->flow_browser); - - evas_object_smart_callback_add - (ephoto->flow_browser, "back", _ephoto_flow_browser_delete, ephoto); + DBG("entry '%s'", entry->path); + ephoto_flow_browser_entry_set(ephoto->flow_browser, entry); + elm_object_focus(ephoto->flow_browser); + evas_object_focus_set(ephoto->flow_browser, EINA_TRUE); // TODO while elm_layout is broken WRT focus + edje_object_signal_emit(ephoto->edje, "flow_browser,show", "ephoto"); ephoto->state = EPHOTO_STATE_FLOW; } +static void +_ephoto_flow_browser_back(void *data, Evas_Object *obj, void *event_info) +{ + Ephoto *ephoto = data; + Ephoto_Entry *entry = event_info; + _ephoto_thumb_browser_show(ephoto, entry); +} + static void _ephoto_thumb_browser_view(void *data, Evas_Object *obj, void *event_info) { @@ -35,7 +42,19 @@ _ephoto_thumb_browser_view(void *data, Evas_Object *obj, void *event_info) } static void -_win_del(void *data, Evas *e, Evas_Object *o, void *event_info) +_pending_path_found(void *data, Ephoto_Entry *entry) +{ + Ephoto *ephoto = data; + if (!entry) + { + ERR("not found entry, but it should be in directory? weird!"); + return; + } + ephoto_flow_browser_entry_set(ephoto->flow_browser, entry); +} + +static void +_win_free(void *data, Evas *e, Evas_Object *o, void *event_info) { Ephoto *ephoto = data; if (ephoto->timer.thumb_regen) ecore_timer_del(ephoto->timer.thumb_regen); @@ -47,7 +66,6 @@ ephoto_window_add(const char *path) { Ephoto *ephoto = calloc(1, sizeof(Ephoto)); Ethumb_Client *client = elm_thumb_ethumb_client_get(); - Evas_Object *ed; Evas_Coord mw, mh, iw, ih; const char *s; EINA_SAFETY_ON_NULL_RETURN_VAL(ephoto, NULL); @@ -60,7 +78,7 @@ ephoto_window_add(const char *path) } evas_object_event_callback_add - (ephoto->win, EVAS_CALLBACK_DEL, _win_del, ephoto); + (ephoto->win, EVAS_CALLBACK_FREE, _win_free, ephoto); elm_win_autodel_set(ephoto->win, EINA_TRUE); evas_object_show(ephoto->win); @@ -94,6 +112,7 @@ ephoto_window_add(const char *path) evas_object_del(ephoto->win); return NULL; } + ephoto->edje = elm_layout_edje_get(ephoto->layout); evas_object_size_hint_weight_set (ephoto->layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_fill_set @@ -110,30 +129,70 @@ ephoto_window_add(const char *path) } elm_layout_content_set (ephoto->layout, "ephoto.swallow.thumb_browser", ephoto->thumb_browser); + evas_object_smart_callback_add + (ephoto->thumb_browser, "view", _ephoto_thumb_browser_view, ephoto); - ed = elm_layout_edje_get(ephoto->layout); - edje_object_size_min_get(ed, &mw, &mh); - edje_object_size_min_restricted_calc(ed, &mw, &mh, mw, mh); + ephoto->flow_browser = ephoto_flow_browser_add(ephoto, ephoto->layout); + if (!ephoto->flow_browser) + { + ERR("could not add flow browser"); + evas_object_del(ephoto->win); + return NULL; + } + elm_layout_content_set + (ephoto->layout, "ephoto.swallow.flow_browser", ephoto->flow_browser); + evas_object_smart_callback_add + (ephoto->flow_browser, "back", _ephoto_flow_browser_back, ephoto); + + edje_object_size_min_get(ephoto->edje, &mw, &mh); + edje_object_size_min_restricted_calc(ephoto->edje, &mw, &mh, mw, mh); if (mw < 1) mw = 320; if (mh < 1) mh = 240; - s = edje_object_data_get(ed, "initial_size"); + s = edje_object_data_get(ephoto->edje, "initial_size"); if ((!s) || (sscanf(s, "%d %d", &iw, &ih) != 2)) iw = ih = 0; if (iw < mw) iw = mw; if (ih < mh) ih = mh; evas_object_resize(ephoto->win, iw, ih); - if (!path) - ephoto_thumb_browser_directory_set - (ephoto->thumb_browser, ephoto->config->directory); + if ((!path) || (!ecore_file_exists(path))) + { + ephoto_thumb_browser_directory_set + (ephoto->thumb_browser, ephoto->config->directory); + _ephoto_thumb_browser_show(ephoto, NULL); + } else if (ecore_file_is_dir(path)) - ephoto_thumb_browser_directory_set(ephoto->thumb_browser, path); + { + ephoto_thumb_browser_directory_set(ephoto->thumb_browser, path); + _ephoto_thumb_browser_show(ephoto, NULL); + } else - ERR("loading file to be done"); + { + char *dir = ecore_file_dir_get(path); + ephoto_thumb_browser_directory_set(ephoto->thumb_browser, dir); + free(dir); + ephoto_thumb_browser_path_pending_set + (ephoto->thumb_browser, path, _pending_path_found, ephoto); + ephoto_flow_browser_path_set(ephoto->flow_browser, path); + + elm_object_focus(ephoto->flow_browser); + evas_object_focus_set(ephoto->flow_browser, EINA_TRUE); // TODO while elm_layout is broken WRT focus + edje_object_signal_emit(ephoto->edje, "flow_browser,show", "ephoto"); + ephoto->state = EPHOTO_STATE_FLOW; + } return ephoto->win; } +void +ephoto_title_set(Ephoto *ephoto, const char *title) +{ + char buf[1024] = "Ephoto"; + + if (title) snprintf(buf, sizeof(buf), "%s - Ephoto", title); + elm_win_title_set(ephoto->win, buf); +} + #if 0 char current_directory[PATH_MAX]; Ethumb_Client *client = elm_thumb_ethumb_client_get(); diff --git a/src/bin/ephoto_thumb_browser.c b/src/bin/ephoto_thumb_browser.c index a5ecb97..8354440 100644 --- a/src/bin/ephoto_thumb_browser.c +++ b/src/bin/ephoto_thumb_browser.c @@ -15,6 +15,11 @@ struct _Ephoto_Thumb_Browser Evas_Object *edje; Evas_Object *grid; Eio_File *ls; + struct { + const char *path; + void (*cb)(void *data, Ephoto_Entry *entry); + const void *data; + } pending; struct { Ecore_Job *change_dir; } job; @@ -147,6 +152,14 @@ _ephoto_populate_main(void *data, const Eina_File_Direct_Info *info) msg.val = eina_list_count(tb->ephoto->entries); edje_object_message_send(tb->edje, EDJE_MESSAGE_INT, 1, &msg); DBG("populate add '%s'", e->path); + + if (tb->pending.path == e->path) + { + tb->pending.cb((void*)tb->pending.data, e); + tb->pending.cb = NULL; + tb->pending.data = NULL; + eina_stringshare_replace(&tb->pending.path, NULL); + } } static Eina_Bool @@ -171,6 +184,14 @@ _ephoto_populate_end(void *data) { Ephoto_Thumb_Browser *tb = data; tb->ls = NULL; + if (tb->pending.cb) + { + tb->pending.cb((void*)tb->pending.data, NULL); + tb->pending.cb = NULL; + } + tb->pending.data = NULL; + eina_stringshare_replace(&tb->pending.path, NULL); + edje_object_signal_emit(tb->edje, "populate,stop", "ephoto"); } static void @@ -178,9 +199,8 @@ _ephoto_populate_error(int error, void *data) { Ephoto_Thumb_Browser *tb = data; if (error) ERR("could not populate: %s", strerror(error)); - tb->ls = NULL; - edje_object_signal_emit(tb->edje, "populate,stop", "ephoto"); edje_object_signal_emit(tb->edje, "populate,error", "ephoto"); + _ephoto_populate_end(tb); } static void @@ -236,6 +256,8 @@ _ephoto_thumb_selected(void *data, Evas_Object *o, void *event_info) Elm_Gengrid_Item *it = event_info; Ephoto_Entry *e = elm_gengrid_item_data_get(it); + elm_gengrid_item_selected_set(it, EINA_FALSE); + if (e->is_dir) ephoto_thumb_browser_directory_set(tb->layout, e->path); else @@ -295,6 +317,8 @@ static void _layout_del(void *data, Evas *e, Evas_Object *o, void *event_info) { Ephoto_Thumb_Browser *tb = data; + if (tb->pending.cb) tb->pending.cb((void*)tb->pending.data, NULL); + eina_stringshare_del(tb->pending.path); if (tb->ls) eio_file_cancel(tb->ls); if (tb->job.change_dir) ecore_job_del(tb->job.change_dir); free(tb); @@ -345,7 +369,7 @@ ephoto_thumb_browser_add(Ephoto *ephoto, Evas_Object *parent) _zoom_set(tb, tb->ephoto->config->thumb_size); - elm_layout_content_set(tb->layout, "ephoto.thumb.swallow", tb->grid); + elm_layout_content_set(tb->layout, "ephoto.swallow.thumb", tb->grid); return layout; @@ -360,7 +384,23 @@ ephoto_thumb_browser_directory_set(Evas_Object *obj, const char *path) Ephoto_Thumb_Browser *tb = evas_object_data_get(obj, "thumb_browser"); EINA_SAFETY_ON_NULL_RETURN(tb); + eina_stringshare_replace(&tb->pending.path, NULL); + tb->pending.cb = NULL; + tb->pending.data = NULL; + + ephoto_title_set(tb->ephoto, path); + eina_stringshare_replace(&tb->ephoto->config->directory, path); if (tb->job.change_dir) ecore_job_del(tb->job.change_dir); tb->job.change_dir = ecore_job_add(_ephoto_thumb_change_dir, tb); } + +void +ephoto_thumb_browser_path_pending_set(Evas_Object *obj, const char *path, void (*cb)(void *data, Ephoto_Entry *entry), const void *data) +{ + Ephoto_Thumb_Browser *tb = evas_object_data_get(obj, "thumb_browser"); + EINA_SAFETY_ON_NULL_RETURN(tb); + eina_stringshare_replace(&tb->pending.path, path); + tb->pending.cb = cb; + tb->pending.data = data; +}