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; +}