From 7a11918ac3b2ce951c37d87b0d56e4ab9845a6fd Mon Sep 17 00:00:00 2001 From: titan Date: Thu, 24 Feb 2011 22:26:47 +0000 Subject: [PATCH] Fix a lot of things in ephoto.. reuse some older code but in a good way. Add in a single image browser. Use externals(ugh, but its faster for some reason?) SVN revision: 57313 --- data/themes/default/ephoto.edc | 901 ++++++++------- data/themes/default/images/Makefile.am | 11 +- data/themes/default/images/bt_sm_base1.png | Bin 477 -> 0 bytes data/themes/default/images/bt_sm_hilight.png | Bin 285 -> 0 bytes data/themes/default/images/bt_sm_shine.png | Bin 275 -> 0 bytes data/themes/default/images/directory-128.png | Bin 5066 -> 0 bytes data/themes/default/images/directory-256.png | Bin 11195 -> 0 bytes data/themes/default/images/directory-512.png | Bin 25515 -> 0 bytes data/themes/default/images/raise.png | Bin 1601 -> 0 bytes data/themes/default/images/up-128.png | Bin 6951 -> 0 bytes data/themes/default/images/up-256.png | Bin 14877 -> 0 bytes data/themes/default/images/up-512.png | Bin 33469 -> 0 bytes src/bin/Makefile.am | 9 +- src/bin/ephoto.c | 85 +- src/bin/ephoto.h | 189 +++- src/bin/ephoto_config.c | 158 +++ src/bin/ephoto_flow_browser.c | 15 +- src/bin/ephoto_main.c | 590 +++++++--- src/bin/ephoto_preferences.c | 189 ++++ src/bin/ephoto_single_browser.c | 1025 ++++++++++++++++++ src/bin/ephoto_slideshow.c | 223 ++-- src/bin/ephoto_thumb_browser.c | 701 +++++++----- 22 files changed, 3112 insertions(+), 984 deletions(-) delete mode 100644 data/themes/default/images/bt_sm_base1.png delete mode 100644 data/themes/default/images/bt_sm_hilight.png delete mode 100644 data/themes/default/images/bt_sm_shine.png delete mode 100644 data/themes/default/images/directory-128.png delete mode 100644 data/themes/default/images/directory-256.png delete mode 100644 data/themes/default/images/directory-512.png delete mode 100644 data/themes/default/images/raise.png delete mode 100644 data/themes/default/images/up-128.png delete mode 100644 data/themes/default/images/up-256.png delete mode 100644 data/themes/default/images/up-512.png create mode 100644 src/bin/ephoto_config.c create mode 100644 src/bin/ephoto_preferences.c create mode 100644 src/bin/ephoto_single_browser.c diff --git a/data/themes/default/ephoto.edc b/data/themes/default/ephoto.edc index e0625f9..79bcd91 100644 --- a/data/themes/default/ephoto.edc +++ b/data/themes/default/ephoto.edc @@ -1,373 +1,530 @@ -collections { - group - { - name: "flow_image"; - image: "thumb_shadow.png" COMP; - parts - { - part - { - name: "event"; - type: RECT; - repeat_events: 1; - description - { - state: "default" 0.0; - color: 0 0 0 0; - } - } - part - { - name: "border-shadow"; - type: IMAGE; - mouse_events: 0; - description - { - state: "default" 0.0; - rel1 - { - to: "image"; - offset: -18 -18; - } - rel2 - { - to: "image"; - offset: 17 17; - } - image - { - normal: "thumb_shadow.png"; - border: 17 17 17 17; - middle: NONE; - } - } - } - part - { - name: "border"; - type: RECT; - mouse_events: 0; - description - { - state: "default" 0.0; - rel1 - { - to: "border-shadow"; - offset: 16 16; - } - rel2 - { - to: "border-shadow"; - offset: -15 -15; - } - } - } - part - { - name: "image"; - type: SWALLOW; - mouse_events: 0; - description - { - state: "default" 0.0; - aspect_preference: BOTH; - aspect: 1.0 1.0; - rel1.offset: 0 8; - rel2.offset: -1 -2; - } - } -// part -// { -// name: "text"; -// type: TEXT; -// effect: SOFT_SHADOW; -// mouse_events: 0; -// scale: 1; -// description -// { -// state: "default" 0.0; -// color: 0 0 0 255; -// color3: 0 0 0 0; -// align: 0.5 1.0; -// rel1 -// { -// relative: 0.0 1.0; -// offset: 20 -30; -// } -// rel2 -// { -// relative: 1.0 1.0; -// offset: -21 -15; -// } -// text -// { -// font: "Sans"; -// size: 10; -// min: 0 1; -// align: 0.5 0.0; -// text_class: "image"; -// } -// } -// } - } - } - group - { - name: "flow"; - parts - { - part - { - name: "offscreen_left"; - type: SWALLOW; - mouse_events: 1; - description - { - state: default 0.0; - fixed: 1 1; - visible: 0; - rel1.relative: 0.0 0.3; - rel1.offset: 0 0; - rel2.relative: 0.0 0.7; - rel2.offset: 0 0; - } - description - { - state: right 0.0; - visible: 1; - rel1.relative: 0.0 0.3; - rel1.offset: 0 0; - rel2.relative: 0.2 0.7; - rel2.offset: 0 0; - } - description - { - state: left 0.0; - visible: 0; - rel1.relative: 1.0 0.3; - rel1.offset: 0 0; - rel2.relative: 1.0 0.7; - rel2.offset: 0 0; - } - } - part - { - name: "left"; - type: SWALLOW; - mouse_events: 1; - description - { - state: default 0.0; - visible: 1; - rel1.relative: 0.0 0.3; - rel1.offset: 0 0; - rel2.relative: 0.2 0.7; - rel2.offset: 0 0; - } - description - { - state: right 0.0; - rel1.relative: 0.2 0.2; - rel1.offset: 0 0; - rel2.relative: 0.8 0.8; - rel2.offset: 0 0; - } - description - { - state: left 0.0; - rel1.relative: 0.0 0.3; - rel1.offset: 0 0; - rel2.relative: 0.0 0.7; - rel2.offset: 0 0; - } - description - { - state: full 0.0; - map.on: 1; - inherit: default 0.0; - visible: 0; - } - } - part - { - name: "right"; - type: SWALLOW; - mouse_events: 1; - description - { - state: default 0.0; - visible: 1; - rel1.relative: 0.8 0.3; - rel1.offset: 0 0; - rel2.relative: 1.0 0.7; - rel2.offset: 0 0; - } - description - { - state: right 0.0; - rel1.relative: 1.0 0.3; - rel1.offset: 0 0; - rel2.relative: 1.0 0.7; - rel2.offset: 0 0; - } - description - { - state: left 0.0; - rel1.relative: 0.2 0.2; - rel1.offset: 0 0; - rel2.relative: 0.8 0.8; - rel2.offset: 0 0; - } - description - { - state: full 0.0; - map.on: 1; - inherit: default 0.0; - visible: 0; - } - } - part - { - name: "center"; - type: SWALLOW; - mouse_events: 1; - description - { - state: default 0.0; - rel1.relative: 0.2 0.2; - rel1.offset: 0 0; - rel2.relative: 0.8 0.8; - rel2.offset: 0 0; - } - description - { - state: right 0.0; - rel1.relative: 0.8 0.3; - rel1.offset: 0 0; - rel2.relative: 1.0 0.7; - rel2.offset: 0 0; - } - description - { - state: left 0.0; - rel1.relative: 0.0 0.3; - rel1.offset: 0 0; - rel2.relative: 0.2 0.7; - rel2.offset: 0 0; - } - description - { - state: full 0.0; - rel1.relative: 0.0 0.0; - rel1.offset: 0 0; - rel2.relative: 1.0 1.0; - rel2.offset: -1 -1; - } - } - part - { - name: "offscreen_right"; - type: SWALLOW; - mouse_events: 1; - description - { - state: default 0.0; - fixed: 1 1; - visible: 0; - rel1.relative: 1.0 0.3; - rel1.offset: 0 0; - rel2.relative: 1.0 0.7; - rel2.offset: 0 0; - } - description - { - state: right 0.0; - visible: 0; - rel1.relative: 0.0 0.3; - rel1.offset: 0 0; - rel2.relative: 0.0 0.7; - rel2.offset: 0 0; - } - description - { - state: left 0.0; - visible: 1; - rel1.relative: 0.8 0.3; - rel1.offset: 0 0; - rel2.relative: 1.0 0.7; - rel2.offset: 0 0; - } - } - } - programs - { - program - { - name: "right"; - signal: "right"; - source: "ephoto"; - action: STATE_SET right 0.0; - transition: LINEAR 0.4; - target: "offscreen_right"; - target: "right"; - target: "center"; - target: "left"; - target: "offscreen_left"; - after: "done"; - } - program - { - name: "left"; - signal: "left"; - source: "ephoto"; - action: STATE_SET left 0.0; - transition: LINEAR 0.4; - target: "offscreen_left"; - target: "left"; - target: "center"; - target: "right"; - target: "offscreen_right"; - after: "done"; - } - program - { - name: "full"; - signal: "full"; - source: "ephoto"; - action: STATE_SET full 0.0; - transition: LINEAR 0.2; - target: "left"; - target: "right"; - target: "center"; - } - program - { - name: "full_reset"; - signal: "full_reset"; - source: "ephoto"; - action: STATE_SET default 0.0; - transition: LINEAR 0.2; - target: "left"; - target: "right"; - target: "center"; - } - program - { - name: "done"; - action: SIGNAL_EMIT "done" "ephoto"; - } - program - { - name: "reset"; - signal: "reset"; - source: "ephoto"; - action: STATE_SET default 0.0; - target: "offscreen_right"; - target: "right"; - target: "center"; - target: "left"; - target: "offscreen_left"; - } - } - } +externals { +external: "elm"; } + +collections { + images + { + image: "thumb_shadow.png" COMP; + } + group + { + name: "elm/layout/ephoto/orient"; + parts + { + part + { + name: "elm.swallow.content"; + type: SWALLOW; + description + { + state: "default" 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; + } + } + description + { + state: "flip_horiz" 0.0; + inherit: "default" 0.0; + map + { + on: 1; + rotation.y : 180; + } + } + description + { + state: "flip_vert" 0.0; + inherit: "default" 0.0; + map + { + on: 1; + rotation.x : 180; + } + } + description + { + state: "flip_horiz_90" 0.0; + inherit: "default" 0.0; + map + { + on: 1; + rotation + { + z: 90; + y: 180; + } + } + } + description + { + state: "flip_vert_90" 0.0; + inherit: "default" 0.0; + map + { + on: 1; + rotation + { + z: 90; + x: 180; + } + } + } + } + programs + { + program + { + signal: "state,rotate,0"; + source: "ephoto"; + action: STATE_SET "rotate_0" 0.0; + target: "elm.swallow.content"; + } + program + { + signal: "state,rotate,90"; + source: "ephoto"; + action: STATE_SET "rotate_90" 0.0; + target: "elm.swallow.content"; + } + program + { + signal: "state,rotate,180"; + source: "ephoto"; + action: STATE_SET "rotate_180" 0.0; + target: "elm.swallow.content"; + } + program + { + signal: "state,rotate,270"; + source: "ephoto"; + action: STATE_SET "rotate_270" 0.0; + target: "elm.swallow.content"; + } + program + { + signal: "state,flip,horiz"; + source: "ephoto"; + action: STATE_SET "flip_horiz" 0.0; + target: "elm.swallow.content"; + } + program + { + signal: "state,flip,vert"; + source: "ephoto"; + action: STATE_SET "flip_vert" 0.0; + target: "elm.swallow.content"; + } + program + { + signal: "state,flip,horiz,90"; + source: "ephoto"; + action: STATE_SET "flip_horiz_90" 0.0; + target: "elm.swallow.content"; + } + program + { + signal: "state,flip,vert,90"; + source: "ephoto"; + action: STATE_SET "flip_vert_90" 0.0; + target: "elm.swallow.content"; + } + } + } + } + group + { + name: "ephoto,thumb,grid"; + parts + { + part + { + name: "ephoto.swallow.content.thumb"; + type: SWALLOW; + mouse_events: 1; + description + { + state: "default" 0.0; + rel1.relative : 0.0 0.0; + rel1.offset : 0 0; + rel2.relative : 1.0 1.0; + rel2.offset : -1 -1; + } + } + } + } + group + { + name: "flow_image"; + parts + { + part + { + name: "event"; + type: RECT; + repeat_events: 1; + description + { + state: "default" 0.0; + color: 0 0 0 0; + } + } + part + { + name: "border-shadow"; + type: IMAGE; + mouse_events: 0; + description + { + state: "default" 0.0; + rel1 + { + to: "image"; + offset: -18 -18; + } + rel2 + { + to: "image"; + offset: 17 17; + } + image + { + normal: "thumb_shadow.png"; + border: 17 17 17 17; + middle: NONE; + } + } + } + part + { + name: "border"; + type: RECT; + mouse_events: 0; + description + { + state: "default" 0.0; + rel1 + { + to: "border-shadow"; + offset: 16 16; + } + rel2 + { + to: "border-shadow"; + offset: -15 -15; + } + } + } + part + { + name: "image"; + type: SWALLOW; + mouse_events: 0; + description + { + state: "default" 0.0; + aspect_preference: BOTH; + aspect: 1.0 1.0; + rel1.offset : 0 8; + rel2.offset : -1 -2; + } + } + } + } + group + { + name: "flow"; + parts + { + part + { + name: "offscreen_left"; + type: SWALLOW; + mouse_events: 1; + description + { + state: default 0.0; + fixed: 1 1; + visible: 0; + rel1.relative : 0.0 0.3; + rel1.offset : 0 0; + rel2.relative : 0.0 0.7; + rel2.offset : 0 0; + } + description + { + state: right 0.0; + visible: 1; + rel1.relative : 0.0 0.3; + rel1.offset : 0 0; + rel2.relative : 0.2 0.7; + rel2.offset : 0 0; + } + description + { + state: left 0.0; + visible: 0; + rel1.relative : 1.0 0.3; + rel1.offset : 0 0; + rel2.relative : 1.0 0.7; + rel2.offset : 0 0; + } + } + part + { + name: "left"; + type: SWALLOW; + mouse_events: 1; + description + { + state: default 0.0; + visible: 1; + rel1.relative : 0.0 0.3; + rel1.offset : 0 0; + rel2.relative : 0.2 0.7; + rel2.offset : 0 0; + } + description + { + state: right 0.0; + rel1.relative : 0.2 0.2; + rel1.offset : 0 0; + rel2.relative : 0.8 0.8; + rel2.offset : 0 0; + } + description + { + state: left 0.0; + rel1.relative : 0.0 0.3; + rel1.offset : 0 0; + rel2.relative : 0.0 0.7; + rel2.offset : 0 0; + } + description + { + state: full 0.0; + inherit: default 0.0; + visible: 0; + } + } + part + { + name: "offscreen_right"; + type: SWALLOW; + mouse_events: 1; + description + { + state: default 0.0; + fixed: 1 1; + visible: 0; + rel1.relative : 1.0 0.3; + rel1.offset : 0 0; + rel2.relative : 1.0 0.7; + rel2.offset : 0 0; + } + description + { + state: right 0.0; + visible: 0; + rel1.relative : 0.0 0.3; + rel1.offset : 0 0; + rel2.relative : 0.0 0.7; + rel2.offset : 0 0; + } + description + { + state: left 0.0; + visible: 1; + rel1.relative : 0.8 0.3; + rel1.offset : 0 0; + rel2.relative : 1.0 0.7; + rel2.offset : 0 0; + } + } + part + { + name: "right"; + type: SWALLOW; + mouse_events: 1; + description + { + state: default 0.0; + visible: 1; + rel1.relative : 0.8 0.3; + rel1.offset : 0 0; + rel2.relative : 1.0 0.7; + rel2.offset : 0 0; + } + description + { + state: right 0.0; + rel1.relative : 1.0 0.3; + rel1.offset : 0 0; + rel2.relative : 1.0 0.7; + rel2.offset : 0 0; + } + description + { + state: left 0.0; + rel1.relative : 0.2 0.2; + rel1.offset : 0 0; + rel2.relative : 0.8 0.8; + rel2.offset : 0 0; + } + description + { + state: full 0.0; + inherit: default 0.0; + visible: 0; + } + } + part + { + name: "center"; + type: SWALLOW; + mouse_events: 1; + description + { + state: default 0.0; + rel1.relative : 0.2 0.2; + rel1.offset : 0 0; + rel2.relative : 0.8 0.8; + rel2.offset : 0 0; + } + description + { + state: right 0.0; + rel1.relative : 0.8 0.3; + rel1.offset : 0 0; + rel2.relative : 1.0 0.7; + rel2.offset : 0 0; + } + description + { + state: left 0.0; + rel1.relative : 0.0 0.3; + rel1.offset : 0 0; + rel2.relative : 0.2 0.7; + rel2.offset : 0 0; + } + description + { + state: full 0.0; + rel1.relative : 0.0 0.0; + rel1.offset : 0 0; + rel2.relative : 1.0 1.0; + rel2.offset : -1 -1; + } + } + } + programs + { + program + { + name: "right"; + signal: "right"; + source: "ephoto"; + action: STATE_SET right 0.0; + transition: LINEAR 0.4; + target: "offscreen_right"; + target: "right"; + target: "center"; + target: "left"; + target: "offscreen_left"; + after: "done"; + } + program + { + name: "left"; + signal: "left"; + source: "ephoto"; + action: STATE_SET left 0.0; + transition: LINEAR 0.4; + target: "offscreen_left"; + target: "left"; + target: "center"; + target: "right"; + target: "offscreen_right"; + after: "done"; + } + program + { + name: "full"; + signal: "full"; + source: "ephoto"; + action: STATE_SET full 0.0; + transition: LINEAR 0.2; + target: "left"; + target: "right"; + target: "center"; + } + program + { + name: "full_reset"; + signal: "full_reset"; + source: "ephoto"; + action: STATE_SET default 0.0; + transition: LINEAR 0.2; + target: "left"; + target: "right"; + target: "center"; + } + program + { + name: "done"; + action: SIGNAL_EMIT "done" "ephoto"; + } + program + { + name: "reset"; + signal: "reset"; + source: "ephoto"; + action: STATE_SET default 0.0; + target: "offscreen_right"; + target: "right"; + target: "center"; + target: "left"; + target: "offscreen_left"; + } + } + } +} + diff --git a/data/themes/default/images/Makefile.am b/data/themes/default/images/Makefile.am index 9df1caa..a3b35fc 100644 --- a/data/themes/default/images/Makefile.am +++ b/data/themes/default/images/Makefile.am @@ -1,14 +1,5 @@ MAINTAINERCLEANFILES = Makefile.in EXTRA_DIST = \ -thumb_shadow.png \ -bt_sm_base1.png \ -bt_sm_shine.png \ -bt_sm_hilight.png \ -up-128.png \ -up-256.png \ -up-512.png \ -directory-128.png \ -directory-256.png \ -directory-512.png +thumb_shadow.png diff --git a/data/themes/default/images/bt_sm_base1.png b/data/themes/default/images/bt_sm_base1.png deleted file mode 100644 index c37e182ed27b9b54dfb24bdeb3d94c585e10f16f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 477 zcmeAS@N?(olHy`uVBq!ia0vp@KrF$*1|$_fl!pK*#^NA%Cx&(BWL^R}Y)RhkE)4%c zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPShY%-+*@x^Snm{4R64!_l=ltB< z)VvY~=c3falGGH1^30M91$R&1fbd2>aiCQeo-U3d7N^%vKI?VFK%{lQiuqhIN6CY8 zqvfxZOT-^-m5x7nbdRh1(SwtgnRU)i(dhdeys^MT^RLBoxx5GS<))T?JJ0X%Ya#E3 zS~EA(b%a>(utI?n6N!RWDRv8%x` znQb1O0!+S_mpoeH!jk>gF+;|kVNS7E5oeT3gpOFcIAcIJM`)<*?DX}vxod5?rdF^9 zHCR41;W=F6;qonQQn2fjw5ug**=vtRbzl3r!>|*@c#Gt=XNgtT2;%R z)99GGfpJ}<^aHJUv&q2~512C=%@0i7ozft+k44ofy`glX(f`a29w(7Bet# z3xhBt!>lO88kb?lj0n31Z52?&a>Ic34L`*eZ!s;n_?V)m~ zkbtc{=aGWWM~AE5zI}J#-KX{9yB274nSQ&GaPRfb$2~TuH=UO5GL+kJc-4G&m)>BG zha8*Z3cJ})9dX&XR(jDg*2I*lYOPv2>H%||OvQxVR|l<-`Lo~YI)6sVo)6qrehZ?- a_b>!XDC}*jKQ{~LDh5wiKbLh*2~7Y831e~q diff --git a/data/themes/default/images/bt_sm_shine.png b/data/themes/default/images/bt_sm_shine.png deleted file mode 100644 index 23bf3110e10797618b2b3ec49c3678405a8c9bd9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 275 zcmeAS@N?(olHy`uVBq!ia0vp@KrF$*1|$_fl!pK*#^NA%Cx&(BWL^R}Y)RhkE)4%c zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPShY%-^*%Wq0U7(O;iEBiObAE1a zYF-J0b5UwyNotBhd1gt5g1e`0KzJjcI8afZr;B5V#p$P$47m;{2(XyuO2wx?4PL`k zxuDKPkzYcZyZC{l0!tIOn6<&3!i+QfnPl!1Go{r8bsS)Ax##>oaP}ky{Tb|&)KU*{ zK5MYq diff --git a/data/themes/default/images/directory-128.png b/data/themes/default/images/directory-128.png deleted file mode 100644 index b9af5f5ffd63d04e64e091015ddbba9923237445..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5066 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 yYfAj46+7rnQfnQl=RD>AFH&`GtgSXpHN diff --git a/data/themes/default/images/directory-256.png b/data/themes/default/images/directory-256.png deleted file mode 100644 index f47b9aebdd4153824943c909b5fbb9edba922d9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11195 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

GYYuM?4oil} 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 diff --git a/data/themes/default/images/raise.png b/data/themes/default/images/raise.png deleted file mode 100644 index 61b2ce9a5310fb03eac84ae2710e20bfca3f9e75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1601 zcmV-H2EO@;P)jN5&vp3=Xo2yjp{$HjMoWQ8Y47Fs_P(5#-{T+cy=VU(0=Vr23Vn)*n=t&##vteH1lGz-Hp)1QD^r zHWv@PAaR6q8t{8Dyt;O)o|-Ozlxjp>d*mDC(WOrnj*Be=;v5?9`Hhx`BKt8w4(JRZ4cn-0$iU~jub!Zz&-7OsDwq4}#34f;`k2mr+g z^(FyaFdk~I68J-4#t^FtyX>QgQ_tw&zx_*nhcccw`e^GWeQ{aX4OS|6}Qz#}-6Ce5dV?@56Wl`02MnQvgJ2cYp?{ra?1kFp8f! zfpJd*LH=2G*~jqA8tpywT>rcX%U5jFYub0oPS~F;%YR#R5l1QaW^rj^@#nODKSnGzZxMj0m z&ibsmeD=-P&K~_;+Nt^?c4YPc7O02sWde6Rwk|Pz;lWF1kAJK8P{+mhj%KHHeH51Wrp|^FbzWS*x zx-%Z5F)B-KQGQMAdU3LcmCKw@9=7=S%ni0U{R(0)WecVmQzx-}zM=F~R5vtmN znsJJgux-0$TOQIK8f2dsIJqxng&IJ@s7d04K;a{^0GP0rE&77-yw9FF`r6g_KMff}Ak zUA^Logu$vHGd7F}@5~B7Cd?8M`_o$(=di&4W;JWPYzd#5mEBqe_XMLh-EI|W2*AN>@ z_?FKvuhS}QL?R-SP&t>Pd9f3XB8fyk8x_#In{a;i1P7Ni)zy|)g@VD;Bi6`B=IPHo z%#Q)1swSuD6o^|z;-y?Df=MLu!nx6WeH(3+)gd<&F{g$GV)Nti%z+)d*~P@igiLPK zsH%#p=5}rui4|WL{#FQ*GXt1szsuUDrPd>L_2E=1?nXz4&B^clf~Vd(PAa!%(gRgB zIe;4pPiHQGxqT7#laI2lv4PcqSg@y(s=yL1V+P&hYN)u1o}rFLB^3fDwn z^(rdv`8YLqHF5hbbu9FK#$qvs_8#QKuU_Fwv1q|{kUxUS9Jmq0HHlbNgD5-j;W zPyjO(Kz><~cy7!`pjdR;08>Df5}#0>;RF8*=LG0fU`oJY00000NkvXXu0mjfTzv$L diff --git a/data/themes/default/images/up-128.png b/data/themes/default/images/up-128.png deleted file mode 100644 index 9bcf1195e5aba6c472f438a67dd2364adbdf0c7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6951 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 diff --git a/data/themes/default/images/up-256.png b/data/themes/default/images/up-256.png deleted file mode 100644 index b6d4f5a403b82c32edf66d78f55beb42ae65a016..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14877 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 O0+i(5$<|1lhx{MlU@w#a diff --git a/data/themes/default/images/up-512.png b/data/themes/default/images/up-512.png deleted file mode 100644 index d76c5642c41ba7c22411457796b932d6d8503d54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33469 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\%ATIiMa&b7Z^dSxSB%Aizwm3C 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 azfq1h`Pw7-+tKj$y@#5*8s%zM!T$$ozR`vN diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 721b736..26860e5 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -16,9 +16,12 @@ endif _sources = \ ephoto.c \ ephoto_main.c \ - ephoto_flow_browser.c \ - ephoto_slideshow.c \ - ephoto_thumb_browser.c + ephoto_config.c \ + ephoto_preferences.c \ + ephoto_thumb_browser.c \ + ephoto_single_browser.c \ + ephoto_flow_browser.c \ + ephoto_slideshow.c _libs = @ELEMENTARY_LIBS@ @EFREET_MIME_LIBS@ @EIO_LIBS@ @EXIF_LIBS@ diff --git a/src/bin/ephoto.c b/src/bin/ephoto.c index 24171f0..b0b5cdc 100644 --- a/src/bin/ephoto.c +++ b/src/bin/ephoto.c @@ -1,9 +1,16 @@ -#include "ephoto.h" - +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include #ifndef ELM_LIB_QUICKLAUNCH +#include "ephoto.h" + static void _ephoto_display_usage(void); +/* Global log domain pointer */ +int __log_domain = -1; + EAPI int elm_main(int argc, char **argv) { @@ -22,58 +29,67 @@ elm_main(int argc, char **argv) elm_need_ethumb(); elm_init(argc, argv); - elm_theme_extension_add(NULL, PACKAGE_DATA_DIR "/themes/default/ephoto.edj"); + elm_theme_extension_add(NULL, PACKAGE_DATA_DIR"/themes/default/ephoto.edj"); + + if (!efreet_mime_init()) + fprintf(stderr, "Could not init efreet_mime!\n"); client = elm_thumb_ethumb_client_get(); if (!client) { - printf("Ephoto could not get ethumb_client; Terminating...\n"); + ERR("could not get ethumb_client"); r = 1; - goto end; + goto end_log_domain; } ethumb_client_crop_align_set(client, 0.5, 0.5); ethumb_client_aspect_set(client, ETHUMB_THUMB_CROP); ethumb_client_orientation_set(client, ETHUMB_THUMB_ORIENT_ORIGINAL); + __log_domain = eina_log_domain_register("ephoto", EINA_COLOR_ORANGE); + if (!__log_domain) + { + EINA_LOG_ERR("Could not register log domain: Ephoto"); + r = 1; + goto end_log_domain; + } elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); + DBG("Logging initialized"); if (argc > 2) { - printf("Too many arguments; Terminating...\n"); + printf("Too Many Arguments!\n"); _ephoto_display_usage(); r = 1; goto end; } - else if (argc == 2) + else if (argc < 2) { - if (!strncmp(argv[1], "--help", 6) || !strncmp(argv[1], "-h", 2)) + Evas_Object *win = ephoto_window_add(NULL); + if (!win) { - _ephoto_display_usage(); - r = 0; + r = 1; goto end; } - else - { - char *real = ecore_file_realpath(argv[1]); - if (!real) - { - printf("Invalid file or directory: '%s'; Terminating...\n", argv[1]); - r = 1; - goto end; - } - if (!ephoto_window_add(real)) - { - printf("Could not create the main window; Terminating...\n"); - goto end; - r = 1; - } - } + } + else if (!strncmp(argv[1], "--help", 6)) + { + _ephoto_display_usage(); + r = 0; + goto end; } else { - if (!ephoto_window_add(NULL)) + char *real = ecore_file_realpath(argv[1]); + if (!real) + { + printf("invalid file or directory: '%s'\n", argv[1]); + r = 1; + goto end; + } + Evas_Object *win = ephoto_window_add(real); + free(real); + if (!win) { - printf("Could not create the main window; Terminating...\n"); r = 1; goto end; } @@ -82,20 +98,25 @@ elm_main(int argc, char **argv) elm_run(); end: + eina_log_domain_unregister(__log_domain); + end_log_domain: + efreet_mime_shutdown(); elm_shutdown(); eio_shutdown(); - + return r; } +/*Display useage commands for ephoto*/ static void _ephoto_display_usage(void) { printf("Ephoto Usage: \n" - "ephoto --help | -h : This page\n" - "ephoto filename : Specifies a file to open\n" - "ephoto directory : Specifies a directory to open\n"); + "ephoto --help : This page\n" + "ephoto filename : Specifies a file to open\n" + "ephoto dirname : Specifies a directory to open\n"); } + #endif ELM_MAIN() diff --git a/src/bin/ephoto.h b/src/bin/ephoto.h index d06905c..b972c50 100644 --- a/src/bin/ephoto.h +++ b/src/bin/ephoto.h @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -15,101 +16,189 @@ #include #include #include -#include #include #include #include #include #include -/*Ephoto Typedefs*/ -typedef struct _Ephoto Ephoto; -typedef struct _Ephoto_Entry Ephoto_Entry; -typedef struct _Ephoto_Event_Entry_Create Ephoto_Event_Entry_Create; -typedef enum _Ephoto_State Ephoto_State; +#define THEME_FILE PACKAGE_DATA_DIR"/themes/default/ephoto.edj" + +typedef struct _Ephoto_Config Ephoto_Config; +typedef struct _Ephoto Ephoto; +typedef struct _Ephoto_Entry Ephoto_Entry; +typedef struct _Ephoto_Event_Entry_Create Ephoto_Event_Entry_Create; + +typedef enum _Ephoto_State Ephoto_State; +typedef enum _Ephoto_Orient Ephoto_Orient; + +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); +void ephoto_directory_set(Ephoto *ephoto, const char *path); + +Ephoto_Orient ephoto_file_orient_get(const char *path); + +Eina_Bool ephoto_config_init(Ephoto *em); +void ephoto_config_save(Ephoto *em, Eina_Bool instant); +void ephoto_config_free(Ephoto *em); + +Evas_Object *ephoto_single_browser_add(Ephoto *ephoto, Evas_Object *parent); +void ephoto_single_browser_entry_set(Evas_Object *obj, Ephoto_Entry *entry); +void ephoto_single_browser_path_pending_set(Evas_Object *obj, const char *path); + /* smart callbacks called: + * "back" - the user wants to go back to the previous screen. + * "slideshow" - the user wants to view a slideshow. + */ + +Evas_Object *ephoto_flow_browser_add(Ephoto *e, Evas_Object *parent); +void ephoto_flow_browser_entry_set(Evas_Object *obj __UNUSED__, Ephoto_Entry *entry); +/* smart callbacks called: + * "back" - the user wants to go back to the previous screen. + * "slideshow" - the user wants to view a slideshow. + */ + +Evas_Object *ephoto_slideshow_add(Ephoto *ephoto, Evas_Object *parent); +void ephoto_slideshow_entry_set(Evas_Object *obj, Ephoto_Entry *entry); + /* smart callbacks called: + * "back" - the user want to go back to the previous screen. + */ + +Evas_Object *ephoto_thumb_browser_add(Ephoto *ephoto, Evas_Object *parent); + +/* smart callbacks called: + * "selected" - an item in the thumb browser is selected. The selected Ephoto_Entry is passed as event_info argument. + */ -/*Ephoto States*/ enum _Ephoto_State { - EPHOTO_STATE_THUMB, - EPHOTO_STATE_FLOW, - EPHOTO_STATE_SLIDESHOW + EPHOTO_STATE_THUMB, + EPHOTO_STATE_FLOW, + EPHOTO_STATE_SINGLE, + EPHOTO_STATE_SLIDESHOW +}; + +enum _Ephoto_Orient /* matches with exif orientation tag */ +{ + EPHOTO_ORIENT_0 = 1, + EPHOTO_ORIENT_FLIP_HORIZ = 2, + EPHOTO_ORIENT_180 = 3, + EPHOTO_ORIENT_FLIP_VERT = 4, + EPHOTO_ORIENT_FLIP_VERT_90 = 5, + EPHOTO_ORIENT_90 = 6, + EPHOTO_ORIENT_FLIP_HORIZ_90 = 7, + EPHOTO_ORIENT_270 = 8 +}; + +/* TODO: split into window & global config, allow multi window + * + * This also requires single instance, as 2 instances changing the + * same configuration will lead to problems. + * + * Single instance is better done as DBus, using FDO standard methods. + */ +struct _Ephoto_Config +{ + int config_version; + const char *editor; + double slideshow_timeout; + const char *slideshow_transition; + + /* these should be per-window */ + int thumb_size; + int thumb_gen_size; + const char *directory; + }; -/*Ephoto Main Structure*/ struct _Ephoto { - /*Main Objects*/ Evas_Object *win; Evas_Object *bg; Evas_Object *pager; - /*Main Children*/ Evas_Object *thumb_browser; Evas_Object *flow_browser; + Evas_Object *single_browser; Evas_Object *slideshow; - /*Main Variables*/ - const char *directory; - Ecore_Job *change_dir; - Ecore_Timer *regen; - Eio_File *ls; Eina_List *entries; + Eina_List *thumbs; /* live thumbs that need to be regenerated on changes */ + + int thumb_gen_size; /* pending value for thumb_regen */ + struct { + Ecore_Timer *thumb_regen; + } timer; + struct { + Ecore_Job *change_dir; + } job; + + Eio_File *ls; + + Evas_Object *prefs_win; Ephoto_State state, prev_state; - Ethumb_Client *client; + + Ephoto_Config *config; }; -/*Ephoto Entry*/ struct _Ephoto_Entry { - /*These variables identify each thumbnail*/ const char *path; - const char *basename; + const char *basename; /* pointer inside path */ const char *label; + Ephoto *ephoto; Elm_Gengrid_Item *item; Eina_List *free_listeners; }; -/*Ephoto Entry Event*/ struct _Ephoto_Event_Entry_Create { Ephoto_Entry *entry; }; -/*Main Functions*/ -Evas_Object *ephoto_window_add(const char *path); -void ephoto_populate(const char *path); -void ephoto_title_set(const char *title); -void ephoto_state_set(Ephoto_State state); -void ephoto_flow_browser_show(Ephoto_Entry *entry); -void ephoto_slideshow_show(Ephoto_Entry *entry); -void ephoto_thumb_browser_show(Ephoto_Entry *entry); -Ephoto_Entry *ephoto_entry_new(const char *path, const char *label); -void ephoto_entry_free(Ephoto_Entry *entry); -void ephoto_entry_free_listener_add(Ephoto_Entry *entry, void (*cb)(void *data, const Ephoto_Entry *entry), const void *data); -void ephoto_entry_free_listener_del(Ephoto_Entry *entry, void (*cb)(void *data, const Ephoto_Entry *entry), const void *data); -void ephoto_entries_free(void); +Ephoto_Entry *ephoto_entry_new(Ephoto *ephoto, const char *path, const char *label); +void ephoto_entry_free(Ephoto_Entry *entry); +void ephoto_entry_free_listener_add(Ephoto_Entry *entry, void (*cb)(void *data, const Ephoto_Entry *entry), const void *data); +void ephoto_entry_free_listener_del(Ephoto_Entry *entry, void (*cb)(void *data, const Ephoto_Entry *entry), const void *data); +void ephoto_entries_free(Ephoto *ephoto); -/*Main Children*/ -Evas_Object *ephoto_flow_browser_add(void); -void ephoto_flow_browser_entry_set(Ephoto_Entry *entry); -void ephoto_flow_browser_del(void); +extern int __log_domain; +#define DBG(...) EINA_LOG_DOM_DBG(__log_domain, __VA_ARGS__) +#define INF(...) EINA_LOG_DOM_INFO(__log_domain, __VA_ARGS__) +#define ERR(...) EINA_LOG_DOM_ERR(__log_domain, __VA_ARGS__) -Evas_Object *ephoto_slideshow_add(void); -void ephoto_slideshow_entry_set(Ephoto_Entry *entry); -void ephoto_slideshow_del(void); +static inline Eina_Bool +_ephoto_eina_file_direct_info_image_useful(const Eina_File_Direct_Info *info) +{ + const char /* *type, */ *bname, *ext; -Evas_Object *ephoto_thumb_browser_add(void); -void ephoto_thumb_browser_entry_set(Ephoto_Entry *entry); -void ephoto_thumb_browser_thumb_append(Eina_List *node); -void ephoto_thumb_browser_del(void); + bname = info->path + info->name_start; + if (bname[0] == '.') return EINA_FALSE; + if ((info->type != EINA_FILE_REG) && (info->type != EINA_FILE_UNKNOWN)) + return EINA_FALSE; + + ext = info->path + info->path_length - 1; + for (; ext > bname; ext--) if (*ext == '.') break; + if (*ext == '.') + { + ext++; + if ((strcasecmp(ext, "jpg") == 0) || + (strcasecmp(ext, "jpeg") == 0) || + (strcasecmp(ext, "png") == 0)) + return EINA_TRUE; + } + + return EINA_FALSE; + /* seems that this does not play nice with threads */ + //if (!(type = efreet_mime_type_get(info->path))) return EINA_FALSE; + //return strncmp(type, "image/", sizeof("image/") - 1) == 0; +} -/*Ephoto Events*/ extern int EPHOTO_EVENT_ENTRY_CREATE; extern int EPHOTO_EVENT_POPULATE_START; extern int EPHOTO_EVENT_POPULATE_END; extern int EPHOTO_EVENT_POPULATE_ERROR; -extern Ephoto *ephoto; - #endif diff --git a/src/bin/ephoto_config.c b/src/bin/ephoto_config.c new file mode 100644 index 0000000..602e2f3 --- /dev/null +++ b/src/bin/ephoto_config.c @@ -0,0 +1,158 @@ +#include "ephoto.h" + +#define CONFIG_VERSION 5 + +static int _ephoto_config_load(Ephoto *ephoto); +static Eina_Bool _ephoto_on_config_save(void *data); + +static Eet_Data_Descriptor *edd = NULL; +static Ecore_Timer *save_timer = NULL; + +Eina_Bool +ephoto_config_init(Ephoto *ephoto) +{ + Eet_Data_Descriptor_Class eddc; + + if (!eet_eina_stream_data_descriptor_class_set(&eddc, sizeof (eddc), "Ephoto_Config", sizeof(Ephoto_Config))) + { + ERR("Unable to create the config data descriptor!"); + return EINA_FALSE; + } + + if (!edd) edd = eet_data_descriptor_stream_new(&eddc); +#undef T +#undef D +#define T Ephoto_Config +#define D edd +#define C_VAL(edd, type, member, dtype) EET_DATA_DESCRIPTOR_ADD_BASIC(edd, type, #member, member, dtype) + C_VAL(D, T, config_version, EET_T_INT); + C_VAL(D, T, thumb_size, EET_T_INT); + C_VAL(D, T, thumb_gen_size, EET_T_INT); + C_VAL(D, T, directory, EET_T_STRING); + C_VAL(D, T, slideshow_timeout, EET_T_DOUBLE); + C_VAL(D, T, slideshow_transition, EET_T_STRING); + C_VAL(D, T, editor, EET_T_STRING); + + switch (_ephoto_config_load(ephoto)) + { + case 0: + /* Start a new config */ + ephoto->config->config_version = CONFIG_VERSION; + ephoto->config->thumb_size = 256; + ephoto->config->thumb_gen_size = 256; + ephoto->config->slideshow_timeout = 4.0; + ephoto->config->slideshow_transition = eina_stringshare_add("fade"); + ephoto->config->editor = eina_stringshare_add("gimp %s"); + break; + + case -1: + /* Incremental additions */ + if (ephoto->config->config_version < 2) + { + ephoto->config->slideshow_timeout = 4.0; + ephoto->config->slideshow_transition = eina_stringshare_add("fade"); + } + if (ephoto->config->config_version < 3) + ephoto->config->editor = eina_stringshare_add("gimp %s"); + + if (ephoto->config->config_version < 5) + ephoto->config->thumb_gen_size = 256; + + ephoto->config->config_version = CONFIG_VERSION; + break; + + default: + return EINA_TRUE; + } + + ephoto_config_save(ephoto, EINA_FALSE); + return EINA_TRUE; +} + +void +ephoto_config_save(Ephoto *ephoto, Eina_Bool instant) +{ + if (save_timer) + { + ecore_timer_del(save_timer); + save_timer = NULL; + } + + if (instant) + _ephoto_on_config_save(ephoto); + else + save_timer = ecore_timer_add(5.0, _ephoto_on_config_save, ephoto); +} + +void +ephoto_config_free(Ephoto *ephoto) +{ + free(ephoto->config); + ephoto->config = NULL; +} + +static int +_ephoto_config_load(Ephoto *ephoto) +{ + Eet_File *ef; + char buf[4096], buf2[4096]; + + snprintf(buf2, sizeof(buf2), "%s/.config/ephoto", getenv("HOME")); + ecore_file_mkpath(buf2); + snprintf(buf, sizeof(buf), "%s/ephoto.cfg", buf2); + + ef = eet_open(buf, EET_FILE_MODE_READ); + if (!ef) + { + ephoto_config_free(ephoto); + ephoto->config = calloc(1, sizeof(Ephoto_Config)); + return 0; + } + + ephoto->config = eet_data_read(ef, edd, "config"); + eet_close(ef); + + if (ephoto->config->config_version > CONFIG_VERSION) + { + ephoto_config_free(ephoto); + ephoto->config = calloc(1, sizeof(Ephoto_Config)); + return 0; + } + + if (ephoto->config->config_version < CONFIG_VERSION) + return -1; + + return 1; +} + +static Eina_Bool +_ephoto_on_config_save(void *data) +{ + Ephoto *ephoto = data; + Eet_File *ef; + char buf[4096], buf2[4096]; + + snprintf(buf, sizeof(buf), "%s/.config/ephoto/ephoto.cfg", getenv("HOME")); + snprintf(buf2, sizeof(buf2), "%s.tmp", buf); + + ef = eet_open(buf2, EET_FILE_MODE_WRITE); + if (!ef) goto save_end; + + eet_data_write(ef, edd, "config", ephoto->config, 1); + if (eet_close(ef)) goto save_end; + + if (!ecore_file_mv(buf2, buf)) goto save_end; + + INF("Config saved"); + +save_end: + ecore_file_unlink(buf2); + + if (save_timer) + { + ecore_timer_del(save_timer); + save_timer = NULL; + } + + return ECORE_CALLBACK_CANCEL; +} diff --git a/src/bin/ephoto_flow_browser.c b/src/bin/ephoto_flow_browser.c index 2519841..b0b1794 100644 --- a/src/bin/ephoto_flow_browser.c +++ b/src/bin/ephoto_flow_browser.c @@ -42,10 +42,11 @@ struct _Ephoto_Flow_Browser } action; }; +Ephoto *ephoto; Ephoto_Flow_Browser *efb; Evas_Object * -ephoto_flow_browser_add(void) +ephoto_flow_browser_add(Ephoto *e, Evas_Object *parent) { int i; @@ -60,7 +61,9 @@ ephoto_flow_browser_add(void) efb->key_down = EINA_FALSE; efb->mouse_wheel = EINA_FALSE; - efb->box = elm_box_add(ephoto->win); + ephoto = e; + + efb->box = elm_box_add(parent); elm_box_horizontal_set(efb->box, EINA_FALSE); elm_box_homogenous_set(efb->box, EINA_FALSE); evas_object_size_hint_weight_set @@ -181,6 +184,8 @@ ephoto_flow_browser_del(void) for (i = 0; i < 5; i++) evas_object_del(efb->images[i]); eina_list_free(efb->items); + if (efb->entry) + ephoto_entry_free_listener_del(efb->entry, _entry_free, NULL); evas_object_del(efb->layout); evas_object_del(efb->toolbar); evas_object_del(efb->box); @@ -188,7 +193,7 @@ ephoto_flow_browser_del(void) } void -ephoto_flow_browser_entry_set(Ephoto_Entry *entry) +ephoto_flow_browser_entry_set(Evas_Object *obj __UNUSED__, Ephoto_Entry *entry) { Eina_Bool same_file = EINA_FALSE; Eina_List *l; @@ -317,7 +322,7 @@ _ephoto_flow_back(void *data __UNUSED__, Evas_Object *o __UNUSED__, void *event_ evas_object_key_ungrab(efb->box, "space", 0, 0); elm_object_unfocus(efb->layout); - ephoto_thumb_browser_show(efb->entry); + evas_object_smart_callback_call(efb->box, "back", efb->entry); } static void @@ -390,7 +395,7 @@ _ephoto_show_slideshow(void *data __UNUSED__, Evas_Object *o __UNUSED__, void *e { elm_toolbar_item_selected_set(efb->action.slideshow, EINA_FALSE); - ephoto_slideshow_show(efb->entry); + evas_object_smart_callback_call(efb->box, "slideshow", efb->entry); } static void diff --git a/src/bin/ephoto_main.c b/src/bin/ephoto_main.c index 6eb57d0..9694afd 100644 --- a/src/bin/ephoto_main.c +++ b/src/bin/ephoto_main.c @@ -1,25 +1,10 @@ #include "ephoto.h" -/*Ephoto Window Callbacks*/ -static void _ephoto_window_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__); - -/*Ephoto Thumb Population Callbacks*/ -static void _ephoto_thumb_populate(void *data __UNUSED__); -static Eina_Bool _ephoto_thumb_populate_filter(void *data __UNUSED__, Eio_File *handler __UNUSED__, const Eina_File_Direct_Info *info); -static void _ephoto_thumb_populate_main(void *data __UNUSED__, Eio_File *handler __UNUSED__, const Eina_File_Direct_Info *info); -static void _ephoto_thumb_populate_end(void *data __UNUSED__, Eio_File *handler __UNUSED__); -static void _ephoto_thumb_populate_error(void *data __UNUSED__, Eio_File *handler __UNUSED__, int error); - -/*Main Ephoto Structure*/ -Ephoto *ephoto; - -/*Ephoto Events*/ int EPHOTO_EVENT_ENTRY_CREATE = 0; int EPHOTO_EVENT_POPULATE_START = 0; int EPHOTO_EVENT_POPULATE_END = 0; int EPHOTO_EVENT_POPULATE_ERROR = 0; -/*Ephoto Entry Listener*/ typedef struct _Ephoto_Entry_Free_Listener Ephoto_Entry_Free_Listener; struct _Ephoto_Entry_Free_Listener { @@ -27,25 +12,182 @@ struct _Ephoto_Entry_Free_Listener const void *data; }; +static void +_ephoto_state_set(Ephoto *ephoto, Ephoto_State state) +{ + ephoto->prev_state = ephoto->state; + ephoto->state = state; +} + +static void +_ephoto_thumb_browser_show(Ephoto *ephoto, Ephoto_Entry *entry) +{ + DBG("entry '%s'", entry ? entry->path : ""); + + ephoto_single_browser_entry_set(ephoto->single_browser, NULL); + ephoto_slideshow_entry_set(ephoto->slideshow, NULL); + elm_pager_content_promote(ephoto->pager, ephoto->thumb_browser); + _ephoto_state_set(ephoto, 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) +{ + DBG("entry '%s'", entry->path); + ephoto_flow_browser_entry_set(ephoto->flow_browser, entry); + elm_pager_content_promote(ephoto->pager, ephoto->flow_browser); + _ephoto_state_set(ephoto, EPHOTO_STATE_FLOW); +} + +static void +_ephoto_single_browser_show(Ephoto *ephoto, Ephoto_Entry *entry) +{ + DBG("entry '%s'", entry->path); + ephoto_single_browser_entry_set(ephoto->single_browser, entry); + elm_pager_content_promote(ephoto->pager, ephoto->single_browser); + _ephoto_state_set(ephoto, EPHOTO_STATE_SINGLE); +} + +static void +_ephoto_slideshow_show(Ephoto *ephoto, Ephoto_Entry *entry) +{ + DBG("entry '%s'", entry->path); + ephoto_slideshow_entry_set(ephoto->slideshow, entry); + elm_pager_content_promote(ephoto->pager, ephoto->slideshow); + _ephoto_state_set(ephoto, EPHOTO_STATE_SLIDESHOW); +} + +static void +_ephoto_single_browser_back(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ephoto *ephoto = data; + Ephoto_Entry *entry = event_info; + _ephoto_thumb_browser_show(ephoto, entry); +} + +static void +_ephoto_flow_browser_back(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ephoto *ephoto = data; + Ephoto_Entry *entry = event_info; + _ephoto_thumb_browser_show(ephoto, entry); +} + +static void +_ephoto_slideshow_back(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ephoto *ephoto = data; + Ephoto_Entry *entry = event_info; + switch (ephoto->prev_state) + { + case EPHOTO_STATE_SINGLE: + _ephoto_single_browser_show(ephoto, entry); + break; + case EPHOTO_STATE_THUMB: + _ephoto_thumb_browser_show(ephoto, entry); + break; + default: + ERR("unhandled previous state %d", ephoto->prev_state); + } + elm_win_fullscreen_set(ephoto->win, EINA_FALSE); +} + +static void +_ephoto_thumb_browser_view(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ephoto *ephoto = data; + Ephoto_Entry *entry = event_info; + _ephoto_single_browser_show(ephoto, entry); +} + +static void +_ephoto_thumb_browser_flow(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ephoto *ephoto = data; + Ephoto_Entry *entry = event_info; + _ephoto_flow_browser_show(ephoto, entry); +} + +static void +_ephoto_thumb_browser_changed_directory(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto *ephoto = data; + ephoto_single_browser_entry_set(ephoto->single_browser, NULL); + ephoto_slideshow_entry_set(ephoto->slideshow, NULL); +} + +static void +_ephoto_thumb_browser_slideshow(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ephoto *ephoto = data; + Ephoto_Entry *entry = event_info; + _ephoto_slideshow_show(ephoto, entry); +} + +static void +_ephoto_flow_browser_slideshow(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ephoto *ephoto = data; + Ephoto_Entry *entry = event_info; + _ephoto_slideshow_show(ephoto, entry); +} + +static void +_ephoto_single_browser_slideshow(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ephoto *ephoto = data; + Ephoto_Entry *entry = event_info; + _ephoto_slideshow_show(ephoto, entry); +} + +static void +_win_free(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto *ephoto = data; + if (ephoto->timer.thumb_regen) ecore_timer_del(ephoto->timer.thumb_regen); + free(ephoto); +} + Evas_Object * ephoto_window_add(const char *path) { + Ephoto *ephoto = calloc(1, sizeof(Ephoto)); + Ethumb_Client *client = elm_thumb_ethumb_client_get(); + char buf[PATH_MAX]; + EINA_SAFETY_ON_NULL_RETURN_VAL(ephoto, NULL); + EPHOTO_EVENT_ENTRY_CREATE = ecore_event_type_new(); EPHOTO_EVENT_POPULATE_START = ecore_event_type_new(); EPHOTO_EVENT_POPULATE_END = ecore_event_type_new(); EPHOTO_EVENT_POPULATE_ERROR = ecore_event_type_new(); - ephoto = calloc(1, sizeof(Ephoto)); - ephoto->client = elm_thumb_ethumb_client_get(); - ephoto->win = elm_win_add(NULL, "ephoto", ELM_WIN_BASIC); if (!ephoto->win) - return NULL; - evas_object_resize(ephoto->win, 600, 480); - ephoto_title_set("Ephoto"); - evas_object_smart_callback_add - (ephoto->win, "delete,request", _ephoto_window_del, NULL); - evas_object_show(ephoto->win); + { + free(ephoto); + return NULL; + } + + evas_object_event_callback_add + (ephoto->win, EVAS_CALLBACK_FREE, _win_free, ephoto); + + elm_win_autodel_set(ephoto->win, EINA_TRUE); + + if (!ephoto_config_init(ephoto)) + { + evas_object_del(ephoto->win); + return NULL; + } + + if ((ephoto->config->thumb_gen_size != 128) && + (ephoto->config->thumb_gen_size != 256) && + (ephoto->config->thumb_gen_size != 512)) + ephoto_thumb_size_set(ephoto, ephoto->config->thumb_size); + else if (client) + ethumb_client_size_set + (client, ephoto->config->thumb_gen_size, ephoto->config->thumb_gen_size); ephoto->bg = elm_bg_add(ephoto->win); evas_object_size_hint_weight_set @@ -55,7 +197,7 @@ ephoto_window_add(const char *path) evas_object_show(ephoto->bg); ephoto->pager = elm_pager_add(ephoto->win); - elm_object_style_set(ephoto->pager, "fade"); + elm_object_style_set(ephoto->pager, "fade_invisible"); evas_object_size_hint_weight_set (ephoto->pager, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_fill_set @@ -63,95 +205,303 @@ ephoto_window_add(const char *path) elm_win_resize_object_add(ephoto->win, ephoto->pager); evas_object_show(ephoto->pager); - ephoto->slideshow = ephoto_slideshow_add(); - elm_pager_content_push(ephoto->pager, ephoto->slideshow); - - ephoto->flow_browser = ephoto_flow_browser_add(); - elm_pager_content_push(ephoto->pager, ephoto->flow_browser); - - ephoto->thumb_browser = ephoto_thumb_browser_add(); + ephoto->thumb_browser = ephoto_thumb_browser_add(ephoto, ephoto->pager); + if (!ephoto->thumb_browser) + { + ERR("could not add thumb browser"); + evas_object_del(ephoto->win); + return NULL; + } elm_pager_content_push(ephoto->pager, ephoto->thumb_browser); + evas_object_smart_callback_add + (ephoto->thumb_browser, "view", _ephoto_thumb_browser_view, ephoto); + evas_object_smart_callback_add + (ephoto->thumb_browser, "flow", _ephoto_thumb_browser_flow, ephoto); + evas_object_smart_callback_add + (ephoto->thumb_browser, "changed,directory", + _ephoto_thumb_browser_changed_directory, ephoto); + evas_object_smart_callback_add + (ephoto->thumb_browser, "slideshow", + _ephoto_thumb_browser_slideshow, ephoto); - elm_pager_content_promote(ephoto->pager, ephoto->thumb_browser); - ephoto->state = EPHOTO_STATE_THUMB; + ephoto->flow_browser = ephoto_flow_browser_add(ephoto, ephoto->pager); + if (!ephoto->flow_browser) + { + ERR("could not add flow browser"); + evas_object_del(ephoto->win); + return NULL; + } + elm_pager_content_push(ephoto->pager, ephoto->flow_browser); + evas_object_smart_callback_add + (ephoto->flow_browser, "back", _ephoto_flow_browser_back, ephoto); + evas_object_smart_callback_add + (ephoto->flow_browser, "slideshow", + _ephoto_flow_browser_slideshow, ephoto); + + ephoto->single_browser = ephoto_single_browser_add(ephoto, ephoto->pager); + if (!ephoto->single_browser) + { + ERR("could not add single browser"); + evas_object_del(ephoto->win); + return NULL; + } + elm_pager_content_push(ephoto->pager, ephoto->single_browser); + evas_object_smart_callback_add + (ephoto->single_browser, "back", _ephoto_single_browser_back, ephoto); + evas_object_smart_callback_add + (ephoto->single_browser, "slideshow", + _ephoto_single_browser_slideshow, ephoto); + + ephoto->slideshow = ephoto_slideshow_add(ephoto, ephoto->pager); + if (!ephoto->slideshow) + { + ERR("could not add slideshow"); + evas_object_del(ephoto->win); + return NULL; + } + elm_pager_content_push(ephoto->pager, ephoto->slideshow); + evas_object_smart_callback_add + (ephoto->slideshow, "back", _ephoto_slideshow_back, ephoto); if ((!path) || (!ecore_file_exists(path))) { - char buf[PATH_MAX]; - - if (getcwd(buf, sizeof(buf))) - path = buf; - else - path = getenv("HOME"); + path = ephoto->config->directory; + if ((path) && (!ecore_file_exists(path))) path = NULL; + if (!path) + { + if (getcwd(buf, sizeof(buf))) + path = buf; + else + path = getenv("HOME"); + } } + if (ecore_file_is_dir(path)) - ephoto_populate(path); + { + ephoto_directory_set(ephoto, path); + _ephoto_thumb_browser_show(ephoto, NULL); + } else { char *dir = ecore_file_dir_get(path); - ephoto_populate(dir); + ephoto_directory_set(ephoto, dir); free(dir); + ephoto_single_browser_path_pending_set(ephoto->single_browser, path); + + elm_pager_content_promote(ephoto->pager, ephoto->single_browser); + ephoto->state = EPHOTO_STATE_SINGLE; } + + /* TODO restore size from last run as well? */ + evas_object_resize(ephoto->win, 900, 600); + evas_object_show(ephoto->win); + return ephoto->win; } void -ephoto_populate(const char *path) +ephoto_title_set(Ephoto *ephoto, const char *title) { - eina_stringshare_replace(&ephoto->directory, path); - if (ephoto->change_dir) ecore_job_del(ephoto->change_dir); - ephoto->change_dir = ecore_job_add(_ephoto_thumb_populate, NULL); + char buf[1024] = "Ephoto"; + + if (title) snprintf(buf, sizeof(buf), "%s - Ephoto", title); + elm_win_title_set(ephoto->win, buf); +} + +static void +_ephoto_populate_main(void *data, Eio_File *handler __UNUSED__, const Eina_File_Direct_Info *info) +{ + Ephoto *ephoto = data; + Ephoto_Entry *e; + Ephoto_Event_Entry_Create *ev; + + e = ephoto_entry_new(ephoto, info->path, info->path + info->name_start); + + ephoto->entries = eina_list_append(ephoto->entries, e); + + ev = calloc(1, sizeof(Ephoto_Event_Entry_Create)); + ev->entry = e; + + ecore_event_add(EPHOTO_EVENT_ENTRY_CREATE, ev, NULL, NULL); +} + +static Eina_Bool +_ephoto_populate_filter(void *data __UNUSED__, Eio_File *handler __UNUSED__, const Eina_File_Direct_Info *info) +{ + const char *bname = info->path + info->name_start; + + if (bname[0] == '.') return EINA_FALSE; + + return _ephoto_eina_file_direct_info_image_useful(info); +} + +static void +_ephoto_populate_end(void *data, Eio_File *handler __UNUSED__) +{ + Ephoto *ephoto = data; + ephoto->ls = NULL; + + ecore_event_add(EPHOTO_EVENT_POPULATE_END, NULL, NULL, NULL); +} + +static void +_ephoto_populate_error(void *data, Eio_File *handler, int error) +{ + Ephoto *ephoto = data; + if (error) ERR("could not populate: %s", strerror(error)); + + /* XXX: Perhaps it would be better to _not_ emit POPULATE_END here */ + ecore_event_add(EPHOTO_EVENT_POPULATE_ERROR, NULL, NULL, NULL); + _ephoto_populate_end(ephoto, handler); +} + +static void +_ephoto_populate_entries(Ephoto *ephoto) +{ + /* Edje_External_Param param; */ + DBG("populate from '%s'", ephoto->config->directory); + + ephoto_entries_free(ephoto); + + ephoto->ls = eio_file_stat_ls(ephoto->config->directory, + _ephoto_populate_filter, + _ephoto_populate_main, + _ephoto_populate_end, + _ephoto_populate_error, + ephoto); + + ecore_event_add(EPHOTO_EVENT_POPULATE_START, NULL, NULL, NULL); +} + +static void +_ephoto_change_dir(void *data) +{ + Ephoto *ephoto = data; + ephoto->job.change_dir = NULL; + _ephoto_populate_entries(ephoto); } void -ephoto_title_set(const char *title) +ephoto_directory_set(Ephoto *ephoto, const char *path) { - elm_win_title_set(ephoto->win, title); + EINA_SAFETY_ON_NULL_RETURN(ephoto); + + ephoto_title_set(ephoto, path); + eina_stringshare_replace(&ephoto->config->directory, path); + if (ephoto->job.change_dir) ecore_job_del(ephoto->job.change_dir); + ephoto->job.change_dir = ecore_job_add(_ephoto_change_dir, ephoto); +} + +static Eina_Bool +_thumb_gen_size_changed_timer_cb(void *data) +{ + Ephoto *ephoto = data; + Ethumb_Client *client; + const Eina_List *l; + Evas_Object *o; + + if (ephoto->config->thumb_gen_size == ephoto->thumb_gen_size) goto end; + + INF("thumbnail generation size changed from %d to %d", + ephoto->config->thumb_gen_size, ephoto->thumb_gen_size); + + client = elm_thumb_ethumb_client_get(); + if (!client) + { + DBG("no client yet, try again later"); + return EINA_TRUE; + } + + ephoto->config->thumb_gen_size = ephoto->thumb_gen_size; + ethumb_client_size_set + (client, ephoto->thumb_gen_size, ephoto->thumb_gen_size); + + EINA_LIST_FOREACH(ephoto->thumbs, l, o) + { + Ethumb_Thumb_Format format; + format = (long)evas_object_data_get(o, "ephoto_format"); + ethumb_client_format_set(client, format); + elm_thumb_reload(o); + } + + end: + ephoto->timer.thumb_regen = NULL; + return EINA_FALSE; } void -ephoto_state_set(Ephoto_State state) +ephoto_thumb_size_set(Ephoto *ephoto, int size) { - ephoto->prev_state = ephoto->state; - ephoto->state = state; + if (ephoto->config->thumb_size != size) + { + INF("thumbnail display size changed from %d to %d", + ephoto->config->thumb_size, size); + ephoto->config->thumb_size = size; + ephoto_config_save(ephoto, EINA_FALSE); + } + + if (size <= 128) ephoto->thumb_gen_size = 128; + else if (size <= 256) ephoto->thumb_gen_size = 256; + else ephoto->thumb_gen_size = 512; + + if (ephoto->timer.thumb_regen) ecore_timer_del(ephoto->timer.thumb_regen); + ephoto->timer.thumb_regen = ecore_timer_add + (0.1, _thumb_gen_size_changed_timer_cb, ephoto); +} + +static void +_thumb_del(void *data, Evas *e __UNUSED__, Evas_Object *o, void *event_info __UNUSED__) +{ + Ephoto *ephoto = data; + ephoto->thumbs = eina_list_remove(ephoto->thumbs, o); +} + +Evas_Object * +ephoto_thumb_add(Ephoto *ephoto, Evas_Object *parent, const char *path) +{ + Evas_Object *o; + + EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL); + + o = elm_thumb_add(parent); + if (!o) return NULL; + + if (path) ephoto_thumb_path_set(o, path); + elm_object_style_set(o, "noframe"); + ephoto->thumbs = eina_list_append(ephoto->thumbs, o); + evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _thumb_del, ephoto); + return o; } void -ephoto_thumb_browser_show(Ephoto_Entry *entry) +ephoto_thumb_path_set(Evas_Object *o, const char *path) { - ephoto_state_set(EPHOTO_STATE_THUMB); - ephoto_flow_browser_entry_set(NULL); - ephoto_slideshow_entry_set(NULL); - elm_pager_content_promote(ephoto->pager, ephoto->thumb_browser); - ephoto_thumb_browser_entry_set(entry); -} + Ethumb_Thumb_Format format = ETHUMB_THUMB_FDO; + const char *ext = strrchr(path, '.'); + if (ext) + { + ext++; + if ((strcasecmp(ext, "jpg") == 0) || + (strcasecmp(ext, "jpeg") == 0)) + format = ETHUMB_THUMB_JPEG; /* faster! */ + } -void -ephoto_flow_browser_show(Ephoto_Entry *entry) -{ - ephoto_state_set(EPHOTO_STATE_FLOW); - elm_pager_content_promote(ephoto->pager, ephoto->flow_browser); - ephoto_flow_browser_entry_set(entry); -} - -void -ephoto_slideshow_show(Ephoto_Entry *entry) -{ - ephoto_state_set(EPHOTO_STATE_SLIDESHOW); - elm_pager_content_promote(ephoto->pager, ephoto->slideshow); - ephoto_slideshow_entry_set(entry); + ethumb_client_format_set(elm_thumb_ethumb_client_get(), format); + evas_object_data_set(o, "ephoto_format", (void*)(long)format); + elm_thumb_file_set(o, path, NULL); } Ephoto_Entry * -ephoto_entry_new(const char *path, const char *label) +ephoto_entry_new(Ephoto *ephoto, const char *path, const char *label) { Ephoto_Entry *entry; - + EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL); entry = calloc(1, sizeof(Ephoto_Entry)); + EINA_SAFETY_ON_NULL_RETURN_VAL(entry, NULL); + entry->ephoto = ephoto; entry->path = eina_stringshare_add(path); entry->basename = ecore_file_file_get(entry->path); entry->label = eina_stringshare_add(label); - return entry; } @@ -165,6 +515,7 @@ ephoto_entry_free(Ephoto_Entry *entry) fl->cb((void *)fl->data, entry); free(fl); } + EINA_SAFETY_ON_NULL_RETURN(entry); eina_stringshare_del(entry->path); eina_stringshare_del(entry->label); free(entry); @@ -174,8 +525,10 @@ void ephoto_entry_free_listener_add(Ephoto_Entry *entry, void (*cb)(void *data, const Ephoto_Entry *entry), const void *data) { Ephoto_Entry_Free_Listener *fl; - + EINA_SAFETY_ON_NULL_RETURN(entry); + EINA_SAFETY_ON_NULL_RETURN(cb); fl = malloc(sizeof(Ephoto_Entry_Free_Listener)); + EINA_SAFETY_ON_NULL_RETURN(fl); fl->cb = cb; fl->data = data; entry->free_listeners = eina_list_append(entry->free_listeners, fl); @@ -186,7 +539,8 @@ ephoto_entry_free_listener_del(Ephoto_Entry *entry, void (*cb)(void *data, const { Eina_List *l; Ephoto_Entry_Free_Listener *fl; - + EINA_SAFETY_ON_NULL_RETURN(entry); + EINA_SAFETY_ON_NULL_RETURN(cb); EINA_LIST_FOREACH(entry->free_listeners, l, fl) { if ((fl->cb == cb) && (fl->data == data)) @@ -199,88 +553,8 @@ ephoto_entry_free_listener_del(Ephoto_Entry *entry, void (*cb)(void *data, const } void -ephoto_entries_free(void) +ephoto_entries_free(Ephoto *ephoto) { Ephoto_Entry *entry; - EINA_LIST_FREE(ephoto->entries, entry) ephoto_entry_free(entry); } - -static void -_ephoto_window_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__) -{ - ephoto_thumb_browser_del(); - ephoto_flow_browser_del(); - ephoto_slideshow_del(); - evas_object_del(ephoto->win); - if (ephoto->regen) - ecore_timer_del(ephoto->regen); - if (ephoto->directory) - eina_stringshare_del(ephoto->directory); - free(ephoto); -} - -static void -_ephoto_thumb_populate(void *data __UNUSED__) -{ - ephoto->change_dir = NULL; - ephoto_entries_free(); - ephoto->ls = eio_file_stat_ls(ephoto->directory, - _ephoto_thumb_populate_filter, - _ephoto_thumb_populate_main, - _ephoto_thumb_populate_end, - _ephoto_thumb_populate_error, - NULL); - ecore_event_add(EPHOTO_EVENT_POPULATE_START, NULL, NULL, NULL); -} - -static Eina_Bool -_ephoto_thumb_populate_filter(void *data __UNUSED__, Eio_File *handler __UNUSED__, const Eina_File_Direct_Info *info) -{ - const char *ext; - - ext = strrchr(info->path, '.'); - if (ext) - { - if ((!strncasecmp(ext, ".jpeg", 5)) || - (!strncasecmp(ext, ".jpg", 4)) || - (!strncasecmp(ext, ".png", 4)) || - (!strncasecmp(ext, ".gif", 4)) || - (!strncasecmp(ext, ".svg", 4))) - return EINA_TRUE; - } - return EINA_FALSE; -} - -static void -_ephoto_thumb_populate_main(void *data __UNUSED__, Eio_File *handler __UNUSED__, const Eina_File_Direct_Info *info) -{ - Ephoto_Entry *e; - Ephoto_Event_Entry_Create *ev; - - e = ephoto_entry_new(info->path, info->path + info->name_start); - ephoto->entries = eina_list_append(ephoto->entries, e); - - ev = calloc(1, sizeof(Ephoto_Event_Entry_Create)); - ev->entry = e; - - ecore_event_add(EPHOTO_EVENT_ENTRY_CREATE, ev, NULL, NULL); -} - -static void -_ephoto_thumb_populate_end(void *data __UNUSED__, Eio_File *handler __UNUSED__) -{ - ephoto->ls = NULL; - - ecore_event_add(EPHOTO_EVENT_POPULATE_END, NULL, NULL, NULL); -} - -static void -_ephoto_thumb_populate_error(void *data __UNUSED__, Eio_File *handler __UNUSED__, int error) -{ - if (error) - printf("Error while populating images: %s\n", strerror(error)); - ecore_event_add(EPHOTO_EVENT_POPULATE_ERROR, NULL, NULL, NULL); - _ephoto_thumb_populate_end(NULL, NULL); -} - diff --git a/src/bin/ephoto_preferences.c b/src/bin/ephoto_preferences.c new file mode 100644 index 0000000..a36c2d1 --- /dev/null +++ b/src/bin/ephoto_preferences.c @@ -0,0 +1,189 @@ +#include "ephoto.h" + +#if 0 +static void _ephoto_preferences_pager_switch(void *data, Evas_Object *obj, void *event_info); +static void _ephoto_preferences_hide(void *data, Evas_Object *obj, void *event_info); +static void _ephoto_preferences_item_change(void *data, Evas_Object *obj, void *event_info); +static void _ephoto_preferences_slideshow_transition(void *data, Evas_Object *obj, void *event_info); + +static void +_ephoto_key_pressed(void *data, Evas *e, Evas_Object *obj, void *event_data) +{ + Evas_Event_Key_Down *eku; + eku = (Evas_Event_Key_Down *)event_data; + if (!strcmp(eku->key, "Escape")) + _ephoto_preferences_hide(data, NULL, NULL); +} + +void +ephoto_show_preferences(Ephoto *em) +{ + if (!em->prefs_win) + { + Evas_Object *o, *tb, *box, *pager, *pg1, *pg2, *pg3, *scr; + const Eina_List *transitions, *l; + const char *transition; + + em->prefs_win = o = elm_win_inwin_add(em->win); + elm_object_style_set(o, "minimal"); + + box = elm_box_add(em->prefs_win); + evas_object_show(box); + evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_inwin_content_set(o, box); + + tb = elm_toolbar_add(box); + elm_toolbar_homogenous_set(tb, EINA_FALSE); + evas_object_size_hint_align_set(tb, EVAS_HINT_FILL, 0.5); + + elm_box_pack_end(box, tb); + evas_object_show(tb); + + pager = elm_pager_add(box); + + pg1 = elm_box_add(pager); + evas_object_size_hint_weight_set(pg1, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(pg1); + elm_pager_content_push(pager, pg1); + evas_object_data_set(pg1, "pager", pager); + elm_toolbar_item_append(tb, NULL, "General", _ephoto_preferences_pager_switch, pg1); + + elm_box_pack_end(box, pager); + evas_object_show(pager); + + pg2 = elm_table_add(pager); + evas_object_size_hint_weight_set(pg2, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(pg2); + elm_pager_content_push(pager, pg2); + evas_object_data_set(pg2, "pager", pager); + elm_toolbar_item_append(tb, NULL, "Slideshow", _ephoto_preferences_pager_switch, pg2); + + o = elm_label_add(pg2); + elm_label_label_set(o, "Delay:"); + evas_object_show(o); + elm_table_pack(pg2, o, 0, 0, 1, 1); + + o = elm_spinner_add(pg2); + elm_spinner_label_format_set(o, "%1.1f seconds"); + elm_spinner_step_set(o, 0.1); + elm_spinner_min_max_set(o, 1.0, 10.0); + elm_spinner_value_set(o, em->config->slideshow_timeout); + evas_object_data_set(o, "config", "slideshow_timeout"); + evas_object_smart_callback_add(o, "delay,changed", + _ephoto_preferences_item_change, em); + evas_object_show(o); + elm_table_pack(pg2, o, 1, 0, 1, 1); + + o = elm_label_add(pg2); + elm_label_label_set(o, "Transition:"); + evas_object_show(o); + elm_table_pack(pg2, o, 0, 1, 1, 1); + + o = elm_hoversel_add(pg2); + elm_hoversel_hover_parent_set(o, em->win); + elm_hoversel_label_set(o, em->config->slideshow_transition); + transitions = elm_slideshow_transitions_get(em->slideshow); + EINA_LIST_FOREACH(transitions, l, transition) + { + elm_hoversel_item_add(o, transition, NULL, ELM_ICON_NONE, _ephoto_preferences_slideshow_transition, em); + } + evas_object_show(o); + elm_table_pack(pg2, o, 1, 1, 1, 1); + + pg3 = elm_box_add(pager); + evas_object_size_hint_weight_set(pg3, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(pg3); + elm_pager_content_push(pager, pg3); + evas_object_data_set(pg3, "pager", pager); + elm_toolbar_item_append(tb, NULL, "External Editor", _ephoto_preferences_pager_switch, pg3); + + o = elm_label_add(pg3); + elm_label_label_set(o, "Image editor:"); + elm_box_pack_end(pg3, o); + evas_object_show(o); + + scr = elm_scroller_add(pg3); + elm_box_pack_end(pg3, scr); + elm_scroller_bounce_set(scr, EINA_TRUE, EINA_FALSE); + evas_object_size_hint_weight_set(scr, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(scr, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(scr); + + o = elm_entry_add(pg3); + elm_entry_single_line_set(o, EINA_TRUE); + evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_entry_entry_set(o, em->config->editor); + evas_object_data_set(o, "config", "editor"); + evas_object_smart_callback_add(o, "changed", + _ephoto_preferences_item_change, em); + elm_scroller_content_set(scr, o); + evas_object_show(o); + + o = elm_button_add(box); + elm_button_label_set(o, "Close"); + evas_object_size_hint_align_set(o, 1.0, 0.5); + evas_object_smart_callback_add(o, "clicked", _ephoto_preferences_hide, em); + elm_box_pack_end(box, o); + evas_object_show(o); + + + evas_object_event_callback_add(em->prefs_win, EVAS_CALLBACK_KEY_DOWN, + _ephoto_key_pressed, em); + + elm_toolbar_item_selected_set(elm_toolbar_first_item_get(tb), + EINA_TRUE); + elm_pager_content_promote(pager, pg1); + } + + elm_win_inwin_activate(em->prefs_win); + evas_object_focus_set(em->prefs_win, EINA_TRUE); +} + +static void +_ephoto_preferences_pager_switch(void *data, Evas_Object *obj, void *event_info) +{ + Evas_Object *o = data; + Evas_Object *pager = evas_object_data_get(o, "pager"); + + elm_pager_content_promote(pager, o); +} + +static void +_ephoto_preferences_item_change(void *data, Evas_Object *obj, void *event_info) +{ + Ephoto *em = data; + const char *key = evas_object_data_get(obj, "config"); + + if (!strcmp(key, "slideshow_timeout")) + em->config->slideshow_timeout = elm_spinner_value_get(obj); + else if (!strcmp(key, "editor")) + eina_stringshare_replace( + &em->config->editor, + eina_stringshare_add(elm_entry_entry_get(obj))); + + ephoto_config_save(em, EINA_FALSE); +} + +static void +_ephoto_preferences_slideshow_transition(void *data, Evas_Object *obj, void *event_info) +{ + Ephoto *em = data; + Elm_Hoversel_Item *it = event_info; + const char *transition = elm_hoversel_item_label_get(it); + + elm_hoversel_label_set(obj, transition); + em->config->slideshow_transition = transition; + ephoto_config_save(em, EINA_FALSE); +} + +static void +_ephoto_preferences_hide(void *data, Evas_Object *obj, void *event_info) +{ + Ephoto *em = data; + + evas_object_hide(em->prefs_win); + evas_object_focus_set(em->thumb_browser, EINA_TRUE); +} + +#endif diff --git a/src/bin/ephoto_single_browser.c b/src/bin/ephoto_single_browser.c new file mode 100644 index 0000000..01080c3 --- /dev/null +++ b/src/bin/ephoto_single_browser.c @@ -0,0 +1,1025 @@ +#include "ephoto.h" + +#ifdef HAVE_LIBEXIF +#include +#endif + +/* ROTATION is disabled until we do it properly, and properly means + * elm_photocam and elm_image rotates their images internally. + * Rotating the scroller is not correct and was rejected by Raster and others. + */ +//#define ROTATION + +#define ZOOM_STEP 0.2 + +typedef struct _Ephoto_Single_Browser Ephoto_Single_Browser; +typedef struct _Ephoto_Viewer Ephoto_Viewer; + +struct _Ephoto_Single_Browser +{ + Ephoto *ephoto; + Evas_Object *layout; + Evas_Object *edje; + Evas_Object *orient_layout; + Evas_Object *orient_edje; + Evas_Object *viewer; + Evas_Object *toolbar; + struct { + Elm_Toolbar_Item *back; + Elm_Toolbar_Item *zoom_in; + Elm_Toolbar_Item *zoom_out; + Elm_Toolbar_Item *zoom_1; + Elm_Toolbar_Item *zoom_fit; + Elm_Toolbar_Item *go_first; + Elm_Toolbar_Item *go_prev; + Elm_Toolbar_Item *go_next; + Elm_Toolbar_Item *go_last; +#ifdef ROTATION + Elm_Toolbar_Item *rotate_counterclock; + Elm_Toolbar_Item *rotate_clock; + Elm_Toolbar_Item *flip_horiz; + Elm_Toolbar_Item *flip_vert; +#endif + Elm_Toolbar_Item *slideshow; + } action; + const char *pending_path; + Ephoto_Entry *entry; + Ephoto_Orient orient; + Eina_List *handlers; +}; + +struct _Ephoto_Viewer +{ + Evas_Object *photocam; + Evas_Object *scroller; + Evas_Object *image; + double zoom; + Eina_Bool fit:1; +}; + +static void _zoom_set(Ephoto_Single_Browser *sb, double zoom); +static void _zoom_in(Ephoto_Single_Browser *sb); +static void _zoom_out(Ephoto_Single_Browser *sb); + +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_photocam_loaded(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) +{ + elm_photocam_paused_set(obj, EINA_FALSE); +} + +static void +_viewer_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + 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; + elm_photocam_paused_set(obj, EINA_TRUE); + evas_object_smart_callback_add + (obj, "loaded", _viewer_photocam_loaded, v); + } + 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_apply(Ephoto_Viewer *v, double zoom) +{ + v->zoom = zoom; + 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 +_viewer_zoom_fit_apply(Ephoto_Viewer *v) +{ + Evas_Coord cw, ch, iw, ih; + double zx, zy, zoom; + + if (v->photocam) + { + evas_object_geometry_get(v->photocam, NULL, NULL, &cw, &ch); + elm_photocam_image_size_get(v->photocam, &iw, &ih); + } + else + { + evas_object_geometry_get(v->scroller, NULL, NULL, &cw, &ch); + evas_object_image_size_get(v->image, &iw, &ih); + } + + if ((cw <= 0) || (ch <= 0)) return; /* object still not resized */ + EINA_SAFETY_ON_TRUE_RETURN(iw <= 0); + EINA_SAFETY_ON_TRUE_RETURN(ih <= 0); + + zx = (double)cw / (double)iw; + zy = (double)ch / (double)ih; + + zoom = (zx < zy) ? zx : zy; + _viewer_zoom_apply(v, zoom); +} + +static void +_viewer_resized(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + _viewer_zoom_fit_apply(data); +} + +static void +_viewer_zoom_set(Evas_Object *obj, double zoom) +{ + Ephoto_Viewer *v = evas_object_data_get(obj, "viewer"); + EINA_SAFETY_ON_NULL_RETURN(v); + _viewer_zoom_apply(v, zoom); + + if (v->fit) + { + if (v->photocam) + evas_object_event_callback_del_full + (v->photocam, EVAS_CALLBACK_RESIZE, _viewer_resized, v); + else + evas_object_event_callback_del_full + (v->scroller, EVAS_CALLBACK_RESIZE, _viewer_resized, v); + v->fit = EINA_FALSE; + } +} + +static double +_viewer_zoom_get(Evas_Object *obj) +{ + Ephoto_Viewer *v = evas_object_data_get(obj, "viewer"); + EINA_SAFETY_ON_NULL_RETURN_VAL(v, 0.0); + return v->zoom; +} + +static void +_viewer_zoom_fit(Evas_Object *obj) +{ + Ephoto_Viewer *v = evas_object_data_get(obj, "viewer"); + EINA_SAFETY_ON_NULL_RETURN(v); + + if (v->fit) return; + v->fit = EINA_TRUE; + + if (v->photocam) + evas_object_event_callback_add + (v->photocam, EVAS_CALLBACK_RESIZE, _viewer_resized, v); + else + evas_object_event_callback_add + (v->scroller, EVAS_CALLBACK_RESIZE, _viewer_resized, v); + + _viewer_zoom_fit_apply(v); +} + +static void +_orient_apply(Ephoto_Single_Browser *sb) +{ +#ifdef ROTATION + const char *sig; + switch (sb->orient) + { + case EPHOTO_ORIENT_0: + sig = "state,rotate,0"; + break; + case EPHOTO_ORIENT_90: + sig = "state,rotate,90"; + break; + case EPHOTO_ORIENT_180: + sig = "state,rotate,180"; + break; + case EPHOTO_ORIENT_270: + sig = "state,rotate,270"; + break; + case EPHOTO_ORIENT_FLIP_HORIZ: + sig = "state,flip,horiz"; + break; + case EPHOTO_ORIENT_FLIP_VERT: + sig = "state,flip,vert"; + break; + case EPHOTO_ORIENT_FLIP_HORIZ_90: + sig = "state,flip,horiz,90"; + break; + case EPHOTO_ORIENT_FLIP_VERT_90: + sig = "state,flip,vert,90"; + break; + default: + return; + } + DBG("orient: %d, signal '%s'", sb->orient, sig); + edje_object_signal_emit(sb->orient_edje, sig, "ephoto"); +#else + (void)sb; +#endif +} + +#ifdef ROTATION +static void +_rotate_counterclock(Ephoto_Single_Browser *sb) +{ + switch (sb->orient) + { + case EPHOTO_ORIENT_0: + sb->orient = EPHOTO_ORIENT_270; + break; + case EPHOTO_ORIENT_90: + sb->orient = EPHOTO_ORIENT_0; + break; + case EPHOTO_ORIENT_180: + sb->orient = EPHOTO_ORIENT_90; + break; + case EPHOTO_ORIENT_270: + sb->orient = EPHOTO_ORIENT_180; + break; + case EPHOTO_ORIENT_FLIP_HORIZ: + sb->orient = EPHOTO_ORIENT_FLIP_HORIZ_90; + break; + case EPHOTO_ORIENT_FLIP_VERT: + sb->orient = EPHOTO_ORIENT_FLIP_VERT_90; + break; + case EPHOTO_ORIENT_FLIP_HORIZ_90: + sb->orient = EPHOTO_ORIENT_FLIP_VERT; + break; + case EPHOTO_ORIENT_FLIP_VERT_90: + sb->orient = EPHOTO_ORIENT_FLIP_HORIZ; + break; + } + _orient_apply(sb); +} + +static void +_rotate_clock(Ephoto_Single_Browser *sb) +{ + switch (sb->orient) + { + case EPHOTO_ORIENT_0: + sb->orient = EPHOTO_ORIENT_90; + break; + case EPHOTO_ORIENT_90: + sb->orient = EPHOTO_ORIENT_180; + break; + case EPHOTO_ORIENT_180: + sb->orient = EPHOTO_ORIENT_270; + break; + case EPHOTO_ORIENT_270: + sb->orient = EPHOTO_ORIENT_0; + break; + case EPHOTO_ORIENT_FLIP_HORIZ: + sb->orient = EPHOTO_ORIENT_FLIP_VERT_90; + break; + case EPHOTO_ORIENT_FLIP_VERT: + sb->orient = EPHOTO_ORIENT_FLIP_HORIZ_90; + break; + case EPHOTO_ORIENT_FLIP_HORIZ_90: + sb->orient = EPHOTO_ORIENT_FLIP_HORIZ; + break; + case EPHOTO_ORIENT_FLIP_VERT_90: + sb->orient = EPHOTO_ORIENT_FLIP_VERT; + break; + } + _orient_apply(sb); +} + +static void +_flip_horiz(Ephoto_Single_Browser *sb) +{ + switch (sb->orient) + { + case EPHOTO_ORIENT_0: + sb->orient = EPHOTO_ORIENT_FLIP_HORIZ; + break; + case EPHOTO_ORIENT_90: + sb->orient = EPHOTO_ORIENT_FLIP_HORIZ_90; + break; + case EPHOTO_ORIENT_180: + sb->orient = EPHOTO_ORIENT_FLIP_VERT; + break; + case EPHOTO_ORIENT_270: + sb->orient = EPHOTO_ORIENT_FLIP_VERT_90; + break; + case EPHOTO_ORIENT_FLIP_HORIZ: + sb->orient = EPHOTO_ORIENT_0; + break; + case EPHOTO_ORIENT_FLIP_VERT: + sb->orient = EPHOTO_ORIENT_180; + break; + case EPHOTO_ORIENT_FLIP_HORIZ_90: + sb->orient = EPHOTO_ORIENT_90; + break; + case EPHOTO_ORIENT_FLIP_VERT_90: + sb->orient = EPHOTO_ORIENT_270; + break; + } + _orient_apply(sb); +} + +static void +_flip_vert(Ephoto_Single_Browser *sb) +{ + switch (sb->orient) + { + case EPHOTO_ORIENT_0: + sb->orient = EPHOTO_ORIENT_FLIP_VERT; + break; + case EPHOTO_ORIENT_90: + sb->orient = EPHOTO_ORIENT_FLIP_VERT_90; + break; + case EPHOTO_ORIENT_180: + sb->orient = EPHOTO_ORIENT_FLIP_HORIZ; + break; + case EPHOTO_ORIENT_270: + sb->orient = EPHOTO_ORIENT_FLIP_HORIZ_90; + break; + case EPHOTO_ORIENT_FLIP_HORIZ: + sb->orient = EPHOTO_ORIENT_180; + break; + case EPHOTO_ORIENT_FLIP_VERT: + sb->orient = EPHOTO_ORIENT_0; + break; + case EPHOTO_ORIENT_FLIP_HORIZ_90: + sb->orient = EPHOTO_ORIENT_270; + break; + case EPHOTO_ORIENT_FLIP_VERT_90: + sb->orient = EPHOTO_ORIENT_90; + break; + } + _orient_apply(sb); +} +#endif + +static void +_mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info) +{ + Ephoto_Single_Browser *sb = data; + Evas_Event_Mouse_Wheel *ev = event_info; + if (!evas_key_modifier_is_set(ev->modifiers, "Control")) return; + + if (ev->z > 0) _zoom_in(sb); + else _zoom_out(sb); +} + +static Ephoto_Entry * +_first_entry_find(Ephoto_Single_Browser *sb) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(sb->ephoto, NULL); + + return eina_list_nth(sb->ephoto->entries, 0); +} + +static Ephoto_Entry * +_last_entry_find(Ephoto_Single_Browser *sb) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(sb->ephoto, NULL); + + return eina_list_data_get(eina_list_last(sb->ephoto->entries)); +} + +static void +_ephoto_single_browser_toolbar_eval(Ephoto_Single_Browser *sb) +{ + if (!sb->entry) + { + elm_toolbar_item_disabled_set(sb->action.go_first, EINA_TRUE); + elm_toolbar_item_disabled_set(sb->action.go_prev, EINA_TRUE); + elm_toolbar_item_disabled_set(sb->action.go_next, EINA_TRUE); + elm_toolbar_item_disabled_set(sb->action.go_last, EINA_TRUE); + elm_toolbar_item_disabled_set(sb->action.slideshow, EINA_TRUE); + } + else + { + Eina_Bool is_first = sb->entry == _first_entry_find(sb); + Eina_Bool is_last = sb->entry == _last_entry_find(sb); + + elm_toolbar_item_disabled_set(sb->action.go_first, is_first); + elm_toolbar_item_disabled_set(sb->action.go_prev, is_first); + elm_toolbar_item_disabled_set(sb->action.go_next, is_last); + elm_toolbar_item_disabled_set(sb->action.go_last, is_last); + elm_toolbar_item_disabled_set(sb->action.slideshow, EINA_FALSE); + } +} + +Ephoto_Orient +ephoto_file_orient_get(const char *path) +{ +#ifndef HAVE_LIBEXIF + return EPHOTO_ORIENT_0; +#else + Ephoto_Orient orient = EPHOTO_ORIENT_0; + ExifData *exif; + ExifEntry *entry; + ExifByteOrder bo; + + if (!_path_is_jpeg(path)) return orient; + + exif = exif_data_new_from_file(path); + if (!exif) goto end; + bo = exif_data_get_byte_order(exif); + entry = exif_data_get_entry(exif, EXIF_TAG_ORIENTATION); + if (!entry) goto end_entry; + + orient = exif_get_short(entry->data, bo); + DBG("orient=%d", orient); + if ((orient < 1) || (orient > 8)) + { + ERR("exif orient not supported: %d", orient); + orient = EPHOTO_ORIENT_0; + } + + end_entry: + exif_data_free(exif); + end: + return orient; +#endif +} + +static void +_ephoto_single_browser_recalc(Ephoto_Single_Browser *sb) +{ + if (sb->viewer) + { + evas_object_del(sb->viewer); + sb->viewer = NULL; + } + + if (sb->entry) + { + const char *bname = ecore_file_file_get(sb->entry->path); + sb->viewer = _viewer_add(sb->orient_layout, sb->entry->path); + elm_layout_content_set + (sb->orient_layout, "elm.swallow.content", sb->viewer); + evas_object_show(sb->viewer); + evas_object_event_callback_add + (sb->viewer, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel, sb); + edje_object_part_text_set(sb->edje, "elm.text.title", bname); + ephoto_title_set(sb->ephoto, bname); + sb->orient = ephoto_file_orient_get(sb->entry->path); + _orient_apply(sb); + } + + elm_object_focus(sb->layout); + + _ephoto_single_browser_toolbar_eval(sb); +} + +static void +_zoom_set(Ephoto_Single_Browser *sb, double zoom) +{ + DBG("zoom %f", zoom); + if (zoom <= 0.0) return; + _viewer_zoom_set(sb->viewer, zoom); +} + +static void +_zoom_fit(Ephoto_Single_Browser *sb) +{ + if (sb->viewer) _viewer_zoom_fit(sb->viewer); +} + +static void +_zoom_in(Ephoto_Single_Browser *sb) +{ + double change = (1.0 + ZOOM_STEP); + _viewer_zoom_set(sb->viewer, _viewer_zoom_get(sb->viewer) * change); +} + +static void +_zoom_out(Ephoto_Single_Browser *sb) +{ + double change = (1.0 - ZOOM_STEP); + _viewer_zoom_set(sb->viewer, _viewer_zoom_get(sb->viewer) * change); +} + +static void +_zoom_in_cb(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + elm_toolbar_item_selected_set(sb->action.zoom_in, EINA_FALSE); + _zoom_in(sb); +} + +static void +_zoom_out_cb(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + elm_toolbar_item_selected_set(sb->action.zoom_out, EINA_FALSE); + _zoom_out(sb); +} + +static void +_zoom_1_cb(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + elm_toolbar_item_selected_set(sb->action.zoom_1, EINA_FALSE); + _zoom_set(sb, 1.0); +} + +static void +_zoom_fit_cb(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + elm_toolbar_item_selected_set(sb->action.zoom_fit, EINA_FALSE); + _zoom_fit(sb); +} + +static int +_entry_cmp(const void *pa, const void *pb) +{ + const Ephoto_Entry *a = pa; + const char *path = pb; + + if (path == a->path) + return 0; + else + return strcoll(a->path, path); +} + +static void +_next_entry(Ephoto_Single_Browser *sb) +{ + Ephoto_Entry *entry = NULL; + Eina_List *node; + EINA_SAFETY_ON_NULL_RETURN(sb->entry); + + node = eina_list_search_sorted_list(sb->ephoto->entries, _entry_cmp, sb->entry->path); + if (!node) return; + while ((node = node->next)) + { + entry = node->data; + } + if (!entry) + entry = _first_entry_find(sb); + if (entry) + { + DBG("next is '%s'", entry->path); + ephoto_single_browser_entry_set(sb->layout, entry); + } +} + +static void +_prev_entry(Ephoto_Single_Browser *sb) +{ + Eina_List *node; + Ephoto_Entry *entry = NULL; + EINA_SAFETY_ON_NULL_RETURN(sb->entry); + + node = eina_list_search_sorted_list(sb->ephoto->entries, _entry_cmp, sb->entry->path); + if (!node) return; + while ((node = node->prev)) + { + entry = node->data; + } + if (!entry) + entry = _last_entry_find(sb); + if (entry) + { + DBG("prev is '%s'", entry->path); + ephoto_single_browser_entry_set(sb->layout, entry); + } +} + +static void +_first_entry(Ephoto_Single_Browser *sb) +{ + Ephoto_Entry *entry = _first_entry_find(sb); + if (!entry) return; + DBG("first is '%s'", entry->path); + ephoto_single_browser_entry_set(sb->layout, entry); +} + +static void +_last_entry(Ephoto_Single_Browser *sb) +{ + Ephoto_Entry *entry = _last_entry_find(sb); + if (!entry) return; + DBG("last is '%s'", entry->path); + ephoto_single_browser_entry_set(sb->layout, entry); +} + +static void +_go_first(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + elm_toolbar_item_selected_set(sb->action.go_first, EINA_FALSE); + _first_entry(sb); +} + +static void +_go_prev(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + elm_toolbar_item_selected_set(sb->action.go_prev, EINA_FALSE); + _prev_entry(sb); +} + +static void +_go_next(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + elm_toolbar_item_selected_set(sb->action.go_next, EINA_FALSE); + _next_entry(sb); +} + +static void +_go_last(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + elm_toolbar_item_selected_set(sb->action.go_last, EINA_FALSE); + _last_entry(sb); +} + +#ifdef ROTATION +static void +_go_rotate_counterclock(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + elm_toolbar_item_selected_set(sb->action.rotate_counterclock, EINA_FALSE); + _rotate_counterclock(sb); +} + +static void +_go_rotate_clock(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + elm_toolbar_item_selected_set(sb->action.rotate_clock, EINA_FALSE); + _rotate_clock(sb); +} + +static void +_go_flip_horiz(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + elm_toolbar_item_selected_set(sb->action.flip_horiz, EINA_FALSE); + _flip_horiz(sb); +} + +static void +_go_flip_vert(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + elm_toolbar_item_selected_set(sb->action.flip_vert, EINA_FALSE); + _flip_vert(sb); +} +#endif + +static void +_slideshow(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + elm_toolbar_item_selected_set(sb->action.slideshow, EINA_FALSE); + if (sb->entry) + evas_object_smart_callback_call(sb->layout, "slideshow", sb->entry); +} + +static void +_back(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + elm_toolbar_item_selected_set(sb->action.back, EINA_FALSE); + evas_object_smart_callback_call(sb->layout, "back", sb->entry); +} + +static void +_key_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info) +{ + Ephoto_Single_Browser *sb = data; + Evas_Event_Key_Down *ev = event_info; + Eina_Bool ctrl = evas_key_modifier_is_set(ev->modifiers, "Control"); + Eina_Bool shift = evas_key_modifier_is_set(ev->modifiers, "Shift"); + const char *k = ev->keyname; + + DBG("key pressed '%s'", k); + if (ctrl) + { + if ((!strcmp(k, "plus")) || (!strcmp(k, "equal"))) + _zoom_in(sb); + else if (!strcmp(k, "minus")) + _zoom_out(sb); + else if (!strcmp(k, "0")) + { + if (shift) _zoom_fit(sb); + else _zoom_set(sb, 1.0); + } + + return; + } + + if (!strcmp(k, "Escape")) + evas_object_smart_callback_call(sb->layout, "back", sb->entry); + else if (!strcmp(k, "Left") || !strcmp(k, "BackSpace")) + _prev_entry(sb); + else if (!strcmp(k, "Right") || !strcmp(k, "space")) + _next_entry(sb); + else if (!strcmp(k, "Home")) + _first_entry(sb); + else if (!strcmp(k, "End")) + _last_entry(sb); +#if ROTATION + else if (!strcmp(k, "bracketleft")) + { + if (!shift) _rotate_counterclock(sb); + else _flip_horiz(sb); + } + else if (!strcmp(k, "bracketright")) + { + if (!shift) _rotate_clock(sb); + else _flip_vert(sb); + } +#endif + else if (!strcmp(k, "F5")) + { + if (sb->entry) + evas_object_smart_callback_call(sb->layout, "slideshow", sb->entry); + } +} + +static void +_entry_free(void *data, const Ephoto_Entry *entry __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + sb->entry = NULL; +} + +static void +_layout_del(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + Ecore_Event_Handler *handler; + + EINA_LIST_FREE(sb->handlers, handler) + ecore_event_handler_del(handler); + if (sb->entry) + ephoto_entry_free_listener_del(sb->entry, _entry_free, sb); + if (sb->pending_path) + eina_stringshare_del(sb->pending_path); + free(sb); +} + +static Elm_Toolbar_Item * +_toolbar_item_add(Ephoto_Single_Browser *sb, const char *icon, const char *label, int priority, Evas_Smart_Cb cb) +{ + Elm_Toolbar_Item *item = elm_toolbar_item_append(sb->toolbar, icon, label, + cb, sb); + elm_toolbar_item_priority_set(item, priority); + return item; +} + +static Elm_Toolbar_Item * +_toolbar_item_separator_add(Ephoto_Single_Browser *sb) +{ + Elm_Toolbar_Item *it = elm_toolbar_item_append + (sb->toolbar, NULL, NULL, NULL, NULL); + elm_toolbar_item_separator_set(it, EINA_TRUE); + return it; +} + +static Eina_Bool +_ephoto_single_populate_end(void *data, int type __UNUSED__, void *event __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + + _ephoto_single_browser_toolbar_eval(sb); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ephoto_single_entry_create(void *data, int type __UNUSED__, void *event __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + Ephoto_Event_Entry_Create *ev = event; + Ephoto_Entry *e; + + e = ev->entry; + if (!sb->entry && sb->pending_path && e->path == sb->pending_path) + { + DBG("Adding entry %p for path %s", e, sb->pending_path); + + eina_stringshare_del(sb->pending_path); + sb->pending_path = NULL; + ephoto_single_browser_entry_set(sb->ephoto->single_browser, e); + } + + return ECORE_CALLBACK_PASS_ON; +} + +Evas_Object * +ephoto_single_browser_add(Ephoto *ephoto, Evas_Object *parent) +{ + Evas_Object *layout = elm_layout_add(parent), *button; + Ephoto_Single_Browser *sb; + + EINA_SAFETY_ON_NULL_RETURN_VAL(layout, NULL); + + sb = calloc(1, sizeof(Ephoto_Single_Browser)); + EINA_SAFETY_ON_NULL_GOTO(sb, error); + sb->ephoto = ephoto; + sb->layout = layout; + sb->edje = elm_layout_edje_get(layout); + evas_object_event_callback_add(layout, EVAS_CALLBACK_DEL, _layout_del, sb); + evas_object_event_callback_add + (layout, EVAS_CALLBACK_KEY_DOWN, _key_down, sb); + evas_object_data_set(layout, "single_browser", sb); + + if (!elm_layout_theme_set + (layout, "layout", "application", "toolbar-content-back")) + { + ERR("could not load style 'toolbar-content-back' from theme"); + goto error; + } + + /*TODO This is hack. Better Idea?*/ + button = edje_object_part_external_object_get(sb->edje, "back"); + evas_object_del(button); + + sb->toolbar = edje_object_part_external_object_get + (sb->edje, "elm.external.toolbar"); + if (!sb->toolbar) + { + ERR("no toolbar in layout!"); + goto error; + } + elm_toolbar_homogenous_set(sb->toolbar, EINA_FALSE); + elm_toolbar_mode_shrink_set(sb->toolbar, ELM_TOOLBAR_SHRINK_MENU); + elm_toolbar_menu_parent_set(sb->toolbar, parent); + + sb->action.back = _toolbar_item_add + (sb, "edit-undo", "Back", 200, _back); + + _toolbar_item_separator_add(sb); + + sb->action.slideshow = _toolbar_item_add + (sb, "media-playback-start", "Slideshow", 150, _slideshow); + + sb->action.zoom_in = _toolbar_item_add + (sb, "zoom-in", "Zoom In", 100, _zoom_in_cb); + sb->action.zoom_out = _toolbar_item_add + (sb, "zoom-out", "Zoom Out", 80, _zoom_out_cb); + sb->action.zoom_1 = _toolbar_item_add + (sb, "zoom-original", "Zoom 1:1", 50, _zoom_1_cb); + sb->action.zoom_fit = _toolbar_item_add + (sb, "zoom-fit-best", "Zoom Fit", 40, _zoom_fit_cb); + + _toolbar_item_separator_add(sb); + + sb->action.go_first = _toolbar_item_add(sb, "go-first", "First", 50, _go_first); + sb->action.go_prev = _toolbar_item_add + (sb, "go-previous", "Previous", 100, _go_prev); + sb->action.go_next = _toolbar_item_add(sb, "go-next", "Next", 50, _go_next); + sb->action.go_last = _toolbar_item_add(sb, "go-last", "Last", 50, _go_last); + + _toolbar_item_separator_add(sb); + +#ifdef ROTATION + sb->action.rotate_counterclock = _toolbar_item_add + (sb, "object-rotate-left", "Rotate Left", 50, _go_rotate_counterclock); + sb->action.rotate_clock = _toolbar_item_add + (sb, "object-rotate-right", "Rotate Right", 30, _go_rotate_clock); + sb->action.flip_horiz = _toolbar_item_add + (sb, "object-flip-horizontal", "Flip Horiz.", 30, _go_flip_horiz); + sb->action.flip_vert = _toolbar_item_add + (sb, "object-flip-vertical", "Flip Vert.", 30, _go_flip_vert); + + elm_toolbar_item_tooltip_text_set + (sb->action.rotate_counterclock, + "Rotate object to the left (counter-clockwise)"); + elm_toolbar_item_tooltip_text_set + (sb->action.rotate_clock, "Rotate object to the right (clockwise)"); + + elm_toolbar_item_tooltip_text_set + (sb->action.flip_horiz, "Flip object horizontally"); + elm_toolbar_item_tooltip_text_set + (sb->action.flip_vert, "Flip object vertically"); +#endif + + sb->orient_layout = elm_layout_add(layout); + if (!elm_layout_theme_set + (sb->orient_layout, "layout", "ephoto", "orient")) + { + ERR("could not load style 'ephoto/orient' from theme"); + goto error; + } + sb->orient_edje = elm_layout_edje_get(sb->orient_layout); + elm_layout_content_set(sb->layout, "elm.swallow.content", sb->orient_layout); + elm_object_focus_custom_chain_append(sb->layout, sb->orient_layout, NULL); + + _ephoto_single_browser_toolbar_eval(sb); + + sb->handlers = eina_list_append + (sb->handlers, ecore_event_handler_add + (EPHOTO_EVENT_POPULATE_END, _ephoto_single_populate_end, sb)); + + sb->handlers = eina_list_append + (sb->handlers, ecore_event_handler_add + (EPHOTO_EVENT_ENTRY_CREATE, _ephoto_single_entry_create, sb)); + + return layout; + + error: + evas_object_del(layout); + return NULL; +} + +void +ephoto_single_browser_entry_set(Evas_Object *obj, Ephoto_Entry *entry) +{ + Ephoto_Single_Browser *sb = evas_object_data_get(obj, "single_browser"); + Eina_Bool same_file = EINA_FALSE; + EINA_SAFETY_ON_NULL_RETURN(sb); + + DBG("entry %p, was %p", entry, sb->entry); + + if (sb->entry) + { + ephoto_entry_free_listener_del(sb->entry, _entry_free, sb); + if (entry && entry->path == sb->entry->path) + same_file = EINA_TRUE; + } + + sb->entry = entry; + + if (entry) + ephoto_entry_free_listener_add(entry, _entry_free, sb); + + if (!sb->entry || same_file) + _ephoto_single_browser_toolbar_eval(sb); + else + { + _ephoto_single_browser_recalc(sb); + _zoom_fit(sb); + } +} + +void +ephoto_single_browser_path_pending_set(Evas_Object *obj, const char *path) +{ + Ephoto_Single_Browser *sb = evas_object_data_get(obj, "single_browser"); + EINA_SAFETY_ON_NULL_RETURN(sb); + + DBG("Setting pending path '%s'", path); + sb->pending_path = eina_stringshare_add(path); +} diff --git a/src/bin/ephoto_slideshow.c b/src/bin/ephoto_slideshow.c index fea7c3a..5041f4f 100644 --- a/src/bin/ephoto_slideshow.c +++ b/src/bin/ephoto_slideshow.c @@ -1,99 +1,192 @@ #include "ephoto.h" -static void _entry_free(void *data __UNUSED__, const Ephoto_Entry *entry __UNUSED__); -static Evas_Object *_ephoto_slideshow_item_get(void *data, Evas_Object *obj); -static void _ephoto_mouse_down(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__); - typedef struct _Ephoto_Slideshow Ephoto_Slideshow; + struct _Ephoto_Slideshow { + Ephoto *ephoto; Evas_Object *slideshow; Ephoto_Entry *entry; }; -static Ephoto_Slideshow *ss; -static const Elm_Slideshow_Item_Class _ephoto_item_cls = {{_ephoto_slideshow_item_get, NULL}}; - -Evas_Object * -ephoto_slideshow_add(void) +static void +_key_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info) { - ss = calloc(1, sizeof(Ephoto_Slideshow)); + Ephoto_Slideshow *ss = data; + Evas_Event_Key_Down *ev = event_info; + const char *k = ev->keyname; - ss->slideshow = elm_slideshow_add(ephoto->win); - elm_slideshow_layout_set(ss->slideshow, "fullscreen"); - elm_slideshow_loop_set(ss->slideshow, EINA_TRUE); - elm_slideshow_transition_set(ss->slideshow, "fade"); - elm_slideshow_timeout_set(ss->slideshow, 5); - evas_object_size_hint_weight_set - (ss->slideshow, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_size_hint_align_set(ss->slideshow, EVAS_HINT_FILL, EVAS_HINT_FILL); - evas_object_event_callback_add - (ss->slideshow, EVAS_CALLBACK_MOUSE_DOWN, _ephoto_mouse_down, NULL); - - return ss->slideshow; -} - -void -ephoto_slideshow_del(void) -{ - if (ss->entry) - ephoto_entry_free_listener_del(ss->entry, _entry_free, NULL); - free(ss); - evas_object_del(ss->slideshow); -} - -void -ephoto_slideshow_entry_set(Ephoto_Entry *entry) -{ - Ephoto_Entry *itr; - Eina_List *l; - - if (ss->entry) - ephoto_entry_free_listener_del(ss->entry, _entry_free, NULL); - ss->entry = entry; - - if (entry) - ephoto_entry_free_listener_add(entry, _entry_free, NULL); - - elm_slideshow_clear(ss->slideshow); - if (!entry) - return; - elm_win_fullscreen_set(ephoto->win, EINA_TRUE); - EINA_LIST_FOREACH(ephoto->entries, l, itr) + if (!strcmp(k, "Escape")) { + Evas_Object *win = ss->ephoto->win; Elm_Slideshow_Item *item; + Ephoto_Entry *entry; - item = elm_slideshow_item_add(ss->slideshow, &_ephoto_item_cls, itr); - if (itr == entry) - elm_slideshow_show(item); + if (elm_win_fullscreen_get(win)) + elm_win_fullscreen_set(win, EINA_FALSE); + + item = elm_slideshow_item_current_get(ss->slideshow); + if (item) entry = elm_slideshow_item_data_get(item); + else entry = ss->entry; + evas_object_smart_callback_call(ss->slideshow, "back", entry); + } + else if (!strcmp(k, "F11")) + { + Evas_Object *win = ss->ephoto->win; + elm_win_fullscreen_set(win, !elm_win_fullscreen_get(win)); } } static void -_entry_free(void *data __UNUSED__, const Ephoto_Entry *entry __UNUSED__) +_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) { + Ephoto_Slideshow *ss = data; + evas_object_smart_callback_call(ss->slideshow, "back", ss->entry); +} + +static void +_entry_free(void *data, const Ephoto_Entry *entry __UNUSED__) +{ + Ephoto_Slideshow *ss = data; ss->entry = NULL; } -static -Evas_Object *_ephoto_slideshow_item_get(void *data, Evas_Object *obj) +static void +_slideshow_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Slideshow *ss = data; + if (ss->entry) + ephoto_entry_free_listener_del(ss->entry, _entry_free, ss); + free(ss); +} + +Evas_Object * +ephoto_slideshow_add(Ephoto *ephoto, Evas_Object *parent) +{ + Evas_Object *slideshow = elm_slideshow_add(parent); + Ephoto_Slideshow *ss; + + EINA_SAFETY_ON_NULL_RETURN_VAL(slideshow, NULL); + + ss = calloc(1, sizeof(Ephoto_Slideshow)); + EINA_SAFETY_ON_NULL_GOTO(ss, error); + ss->ephoto = ephoto; + ss->slideshow = slideshow; + evas_object_event_callback_add + (slideshow, EVAS_CALLBACK_DEL, _slideshow_del, ss); + evas_object_event_callback_add + (slideshow, EVAS_CALLBACK_KEY_DOWN, _key_down, ss); + evas_object_event_callback_add + (slideshow, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, ss); + evas_object_data_set(slideshow, "slideshow", ss); + + elm_slideshow_loop_set(slideshow, EINA_TRUE); + elm_slideshow_layout_set(slideshow, "fullscreen"); + evas_object_size_hint_weight_set + (slideshow, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(slideshow, EVAS_HINT_FILL, EVAS_HINT_FILL); + + return ss->slideshow; + + error: + evas_object_del(slideshow); + return NULL; +} + +static void +_image_resized(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *image, void *event_info __UNUSED__) +{ + Evas_Map *map = evas_map_new(4); + Evas_Coord cx, cy, x, y, w, h; + int orient = (long)evas_object_data_get(image, "orient"); + + evas_object_geometry_get(image, &x, &y, &w, &h); + evas_map_util_points_populate_from_geometry(map, x, y, w, h, 0); + cx = x + w / 2; + cy = y + h / 2; + + switch (orient) + { + case EPHOTO_ORIENT_0: + break; + case EPHOTO_ORIENT_90: + evas_map_util_rotate(map, 90.0, cx, cy); + evas_object_map_enable_set(image, EINA_TRUE); + evas_object_map_set(image, map); + printf("rotated 90 around %d,%d (%dx%d)\n", cx, cy, w, h); + break; + case EPHOTO_ORIENT_180: + evas_map_util_rotate(map, 180.0, cx, cy); + evas_object_map_enable_set(image, EINA_TRUE); + evas_object_map_set(image, map); + printf("rotated 180 around %d,%d (%d,%d %dx%d)\n", cx, cy, x, y, w, h); + break; + case EPHOTO_ORIENT_270: + evas_map_util_rotate(map, 270.0, cx, cy); + evas_object_map_enable_set(image, EINA_TRUE); + evas_object_map_set(image, map); + printf("rotated 270 around %d,%d (%dx%d)\n", cx, cy, w, h); + break; + default: + ERR("unknown orient %d", orient); + } + + evas_map_free(map); +} + +static Evas_Object * +_slideshow_item_get(void *data, Evas_Object *obj) { Ephoto_Entry *entry = data; - + /* TODO use viewer from ephoto_single_browser.c */ + /* TODO consider using exif rotation, see ephoto_single_browser.c */ Evas_Object *image = elm_photo_add(obj); elm_photo_file_set(image, entry->path); elm_photo_fill_inside_set(image, EINA_TRUE); elm_object_style_set(image, "shadow"); + evas_object_data_set + (image, "orient", (void*)(long)ephoto_file_orient_get(entry->path)); + evas_object_event_callback_add + (image, EVAS_CALLBACK_RESIZE, _image_resized, NULL); + return image; } -static void -_ephoto_mouse_down(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +static const Elm_Slideshow_Item_Class _item_cls = {{_slideshow_item_get, NULL}}; + +void +ephoto_slideshow_entry_set(Evas_Object *obj, Ephoto_Entry *entry) { - elm_win_fullscreen_set(ephoto->win, EINA_FALSE); - if (ephoto->prev_state == EPHOTO_STATE_THUMB) - ephoto_thumb_browser_show(ss->entry); - else if (ephoto->prev_state == EPHOTO_STATE_FLOW) - ephoto_flow_browser_show(ss->entry); + Ephoto_Slideshow *ss = evas_object_data_get(obj, "slideshow"); + Ephoto_Config *conf; + Ephoto_Entry *itr; + const Eina_List *l; + EINA_SAFETY_ON_NULL_RETURN(ss); + + conf = ss->ephoto->config; + + DBG("entry %p, was %p", entry, ss->entry); + + if (ss->entry) + ephoto_entry_free_listener_del(ss->entry, _entry_free, ss); + + ss->entry = entry; + + if (entry) + ephoto_entry_free_listener_add(entry, _entry_free, ss); + + elm_slideshow_loop_set(ss->slideshow, EINA_TRUE); /* move to config? */ + elm_slideshow_transition_set(ss->slideshow, conf->slideshow_transition); + elm_slideshow_timeout_set(ss->slideshow, conf->slideshow_timeout); + elm_slideshow_clear(ss->slideshow); + if (!entry) return; + + elm_win_fullscreen_set(ss->ephoto->win, EINA_TRUE); + EINA_LIST_FOREACH(ss->ephoto->entries, l, itr) + { + Elm_Slideshow_Item *item; + item = elm_slideshow_item_add(ss->slideshow, &_item_cls, itr); + if (itr == entry) elm_slideshow_show(item); + } } diff --git a/src/bin/ephoto_thumb_browser.c b/src/bin/ephoto_thumb_browser.c index 95add25..c313915 100644 --- a/src/bin/ephoto_thumb_browser.c +++ b/src/bin/ephoto_thumb_browser.c @@ -1,375 +1,498 @@ #include "ephoto.h" #define ZOOM_MAX 512 -#define ZOOM_MED 256 #define ZOOM_MIN 128 -#define ZOOM_START 192 #define ZOOM_STEP 32 + #define TODO_ITEM_MIN_BATCH 16 -static void _todo_items_free(void); -static void _grid_items_free(void); -static void _entry_item_add(Ephoto_Entry *e); -static Eina_Bool _todo_items_process(void *data __UNUSED__); -static Eina_Bool _ephoto_thumb_entry_create(void *data __UNUSED__, int type __UNUSED__, void *event); -static Eina_Bool _ephoto_thumb_populate_error(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__); -static Eina_Bool _ephoto_thumb_populate_end(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__); -static Eina_Bool _ephoto_thumb_populate_start(void *data, int type __UNUSED__, void *event __UNUSED__); -static Evas_Object *_ephoto_thumbnail_icon_get(void *data, Evas_Object *obj __UNUSED__, const char *part __UNUSED__); -static char *_ephoto_thumbnail_label_get(void *data, Evas_Object *obj __UNUSED__, const char *part __UNUSED__); -static void _ephoto_thumbnail_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__); -static void _ephoto_change_dir(void *data __UNUSED__, Evas_Object *o __UNUSED__, void *event_info); -static void _ephoto_zoom_in(void *data __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__); -static void _ephoto_zoom_out(void *data __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__); -static void _ephoto_show_flow(void *data __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__); -static void _ephoto_show_slideshow(void *data __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__); - -static const Elm_Gengrid_Item_Class _ephoto_thumbnail_class = { - "thumb", - { - _ephoto_thumbnail_label_get, - _ephoto_thumbnail_icon_get, - NULL, - _ephoto_thumbnail_del - } - }; +#define PARENT_DIR "Up" typedef struct _Ephoto_Thumb_Browser Ephoto_Thumb_Browser; + struct _Ephoto_Thumb_Browser { - Evas_Object *box; - Evas_Object *dir_entry; + Ephoto *ephoto; + Evas_Object *layout; + Evas_Object *edje; + Evas_Object *fsel; Evas_Object *grid; Evas_Object *toolbar; - Eina_List *handlers; + Evas_Object *overlay; + Eio_File *ls; Eina_List *todo_items; Eina_List *grid_items; - Eio_File *ls; - int thumb_size; + Eina_List *handlers; struct { + Elm_Toolbar_Item *flow; Elm_Toolbar_Item *zoom_in; Elm_Toolbar_Item *zoom_out; - Elm_Toolbar_Item *view_flow; + Elm_Toolbar_Item *view_single; Elm_Toolbar_Item *slideshow; } action; struct { - Ecore_Animator *todo_items; + Ecore_Animator *todo_items; } animator; + Eina_Bool layout_deleted : 1; }; -Ephoto_Thumb_Browser *etb; - -Evas_Object * -ephoto_thumb_browser_add(void) +static void +_todo_items_free(Ephoto_Thumb_Browser *tb) { - etb = calloc(1, sizeof(Ephoto_Thumb_Browser)); - etb->thumb_size = ZOOM_START; - - etb->box = elm_box_add(ephoto->win); - elm_box_horizontal_set(etb->box, EINA_FALSE); - elm_box_homogenous_set(etb->box, EINA_FALSE); - evas_object_size_hint_weight_set - (etb->box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - elm_win_resize_object_add(ephoto->win, etb->box); - evas_object_show(etb->box); - - etb->toolbar = elm_toolbar_add(etb->box); - elm_toolbar_homogenous_set(etb->toolbar, EINA_TRUE); - elm_toolbar_mode_shrink_set(etb->toolbar, ELM_TOOLBAR_SHRINK_MENU); - elm_toolbar_menu_parent_set(etb->toolbar, etb->box); - evas_object_size_hint_weight_set(etb->toolbar, 0.0, 0.0); - evas_object_size_hint_align_set(etb->toolbar, EVAS_HINT_FILL, 0.0); - - etb->action.zoom_in = elm_toolbar_item_append - (etb->toolbar, "add", "Zoom In", _ephoto_zoom_in, NULL); - elm_toolbar_item_priority_set(etb->action.zoom_in, 0); - etb->action.zoom_out = elm_toolbar_item_append - (etb->toolbar, "remove", "Zoom Out", _ephoto_zoom_out, NULL); - elm_toolbar_item_priority_set(etb->action.zoom_out, 1); - etb->action.view_flow = elm_toolbar_item_append - (etb->toolbar, "image", "View Flow", _ephoto_show_flow, NULL); - elm_toolbar_item_priority_set(etb->action.view_flow, 2); - etb->action.slideshow = elm_toolbar_item_append - (etb->toolbar, "media-playback-start", "Slideshow", _ephoto_show_slideshow, NULL); - elm_toolbar_item_priority_set(etb->action.slideshow, 3); - - elm_toolbar_icon_size_set(etb->toolbar, 32); - elm_box_pack_end(etb->box, etb->toolbar); - evas_object_show(etb->toolbar); - - etb->dir_entry = elm_fileselector_entry_add(etb->box); - elm_fileselector_entry_path_set(etb->dir_entry, ephoto->directory); - elm_fileselector_entry_button_label_set(etb->dir_entry, "Choose"); - elm_fileselector_entry_is_save_set(etb->dir_entry, EINA_FALSE); - elm_fileselector_entry_inwin_mode_set(etb->dir_entry, EINA_TRUE); - evas_object_size_hint_weight_set(etb->dir_entry, 0.0, 0.0); - evas_object_size_hint_align_set(etb->dir_entry, EVAS_HINT_FILL, 0.0); - evas_object_smart_callback_add - (etb->dir_entry, "file,chosen", _ephoto_change_dir, NULL); - elm_box_pack_end(etb->box, etb->dir_entry); - evas_object_show(etb->dir_entry); - - etb->grid = elm_gengrid_add(etb->box); - elm_gengrid_align_set(etb->grid, 0.5, 0.5); - elm_gengrid_bounce_set(etb->grid, EINA_FALSE, EINA_TRUE); - elm_gengrid_item_size_set(etb->grid, etb->thumb_size, etb->thumb_size); - evas_object_size_hint_align_set - (etb->grid, EVAS_HINT_FILL, EVAS_HINT_FILL); - evas_object_size_hint_weight_set - (etb->grid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - elm_box_pack_end(etb->box, etb->grid); - evas_object_smart_callback_add(etb->grid, "clicked", _ephoto_show_flow, NULL); - evas_object_show(etb->grid); - - etb->handlers = eina_list_append - (etb->handlers, ecore_event_handler_add - (EPHOTO_EVENT_POPULATE_START, _ephoto_thumb_populate_start, NULL)); - - - etb->handlers = eina_list_append - (etb->handlers, ecore_event_handler_add - (EPHOTO_EVENT_POPULATE_END, _ephoto_thumb_populate_end, NULL)); - - etb->handlers = eina_list_append - (etb->handlers, ecore_event_handler_add - (EPHOTO_EVENT_POPULATE_ERROR, _ephoto_thumb_populate_error, NULL)); - - etb->handlers = eina_list_append - (etb->handlers, ecore_event_handler_add - (EPHOTO_EVENT_ENTRY_CREATE, _ephoto_thumb_entry_create, NULL)); - - return etb->box; -} - -void -ephoto_thumb_browser_entry_set(Ephoto_Entry *entry) -{ - if ((entry) && (entry->item)) - elm_gengrid_item_bring_in(entry->item); -} - -void -ephoto_thumb_browser_del(void) -{ - Ecore_Event_Handler *handler; - - evas_object_del(etb->box); - _todo_items_free(); - _grid_items_free(); - EINA_LIST_FREE(etb->handlers, handler) - ecore_event_handler_del(handler); - if (etb->animator.todo_items) - { - ecore_animator_del(etb->animator.todo_items); - etb->animator.todo_items = NULL; - } - if (etb->ls) - { - eio_file_cancel(etb->ls); - return; - } - free(etb); + eina_list_free(tb->todo_items); + tb->todo_items = NULL; } static void -_todo_items_free() +_grid_items_free(Ephoto_Thumb_Browser *tb) { - eina_list_free(etb->todo_items); - etb->todo_items = NULL; + eina_list_free(tb->grid_items); + tb->grid_items = NULL; +} + +static Ephoto_Entry * +_first_file_entry_find(Ephoto_Thumb_Browser *tb) +{ + return eina_list_nth(tb->ephoto->entries, 0); +} + +static char * +_ephoto_thumb_item_label_get(void *data, Evas_Object *obj __UNUSED__, const char *part __UNUSED__) +{ + Ephoto_Entry *e = data; + return strdup(e->label); +} + + +static Evas_Object * +_ephoto_thumb_file_icon_get(void *data, Evas_Object *obj, const char *part __UNUSED__) +{ + Ephoto_Entry *e = data; + return ephoto_thumb_add(e->ephoto, obj, e->path); } static void -_grid_items_free() +_ephoto_thumb_item_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__) { - eina_list_free(etb->grid_items); - etb->grid_items = NULL; + /* FIXME: the entry is already freed when changing directories + * One solution is to take care of this cleaning when manually removing + * some grid items + Ephoto_Entry *e = data; + e->item = NULL; + */ } -static void -_entry_item_add(Ephoto_Entry *e) -{ - const Elm_Gengrid_Item_Class *ic = &_ephoto_thumbnail_class; +static const Elm_Gengrid_Item_Class _ephoto_thumb_file_class = { + "thumb", + { + _ephoto_thumb_item_label_get, + _ephoto_thumb_file_icon_get, + NULL, + _ephoto_thumb_item_del + } +}; - e->item = elm_gengrid_item_append(etb->grid, ic, e, NULL, NULL); - etb->grid_items = eina_list_append(etb->grid_items, e->item); +static void +_entry_item_add(Ephoto_Thumb_Browser *tb, Ephoto_Entry *e) +{ + const Elm_Gengrid_Item_Class *ic; + + ic = &_ephoto_thumb_file_class; + + e->item = elm_gengrid_item_append(tb->grid, ic, e, NULL, NULL); + tb->grid_items = eina_list_append(tb->grid_items, e->item); if (e->item) elm_gengrid_item_data_set(e->item, e); else - ephoto_entry_free(e); + { + ERR("could not add item to grid: path '%s'", e->path); + ephoto_entry_free(e); + return; + } } static Eina_Bool -_todo_items_process(void *data __UNUSED__) +_todo_items_process(void *data) { + Ephoto_Thumb_Browser *tb = data; + Edje_Message_Int msg; Ephoto_Entry *entry; - if ((etb->ls) && (eina_list_count(etb->todo_items) < TODO_ITEM_MIN_BATCH)) + if ((tb->ls) && (eina_list_count(tb->todo_items) < TODO_ITEM_MIN_BATCH)) return EINA_TRUE; - etb->animator.todo_items = NULL; - EINA_LIST_FREE(etb->todo_items, entry) - _entry_item_add(entry); + tb->animator.todo_items = NULL; + + EINA_LIST_FREE(tb->todo_items, entry) + _entry_item_add(tb, entry); + + msg.val = eina_list_count(tb->ephoto->entries); + edje_object_message_send(tb->edje, EDJE_MESSAGE_INT, 1, &msg); + return EINA_FALSE; } -static Eina_Bool -_ephoto_thumb_populate_start(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) +static void +_ephoto_thumb_selected(void *data, Evas_Object *o __UNUSED__, void *event_info) { - _todo_items_free(); - _grid_items_free(); - elm_gengrid_clear(etb->grid); - elm_fileselector_entry_path_set(etb->dir_entry, ephoto->directory); + Ephoto_Thumb_Browser *tb = data; + Elm_Gengrid_Item *it = event_info; + Ephoto_Entry *e = elm_gengrid_item_data_get(it); + + elm_gengrid_item_selected_set(it, EINA_FALSE); + + evas_object_smart_callback_call(tb->layout, "view", e); +} + +static void +_changed_dir(void *data, Evas_Object *o __UNUSED__, void *event_info) +{ + Ephoto_Thumb_Browser *tb = data; + const char *path = event_info; + if (!path) return; + ephoto_directory_set(tb->ephoto, path); +} + +static void +_changed_dir_text(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Thumb_Browser *tb = data; + const char *path = elm_fileselector_entry_path_get(tb->fsel); + if (ecore_file_is_dir(path)) + ephoto_directory_set(tb->ephoto, path); +} + +static void +_zoom_set(Ephoto_Thumb_Browser *tb, int zoom) +{ + if (zoom > ZOOM_MAX) zoom = ZOOM_MAX; + else if (zoom < ZOOM_MIN) zoom = ZOOM_MIN; + + ephoto_thumb_size_set(tb->ephoto, zoom); + elm_gengrid_item_size_set(tb->grid, zoom, zoom); + + elm_toolbar_item_disabled_set(tb->action.zoom_out, zoom == ZOOM_MIN); + elm_toolbar_item_disabled_set(tb->action.zoom_in, zoom == ZOOM_MAX); +} + +static void +_zoom_in(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Thumb_Browser *tb = data; + elm_toolbar_item_selected_set(tb->action.zoom_in, EINA_FALSE); + _zoom_set(tb, tb->ephoto->config->thumb_size + ZOOM_STEP); +} + +static void +_zoom_out(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Thumb_Browser *tb = data; + elm_toolbar_item_selected_set(tb->action.zoom_out, EINA_FALSE); + _zoom_set(tb, tb->ephoto->config->thumb_size - ZOOM_STEP); +} + +static void +_view_single(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Thumb_Browser *tb = data; + Elm_Gengrid_Item *it = elm_gengrid_selected_item_get(tb->grid); + Ephoto_Entry *entry; + + elm_toolbar_item_selected_set(tb->action.view_single, EINA_FALSE); + + if (it) entry = elm_gengrid_item_data_get(it); + else entry = _first_file_entry_find(tb); + + if (!entry) return; + evas_object_smart_callback_call(tb->layout, "view", entry); +} + +static void +_slideshow(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Thumb_Browser *tb = data; + Elm_Gengrid_Item *it = elm_gengrid_selected_item_get(tb->grid); + Ephoto_Entry *entry; + + elm_toolbar_item_selected_set(tb->action.slideshow, EINA_FALSE); + + if (it) entry = elm_gengrid_item_data_get(it); + else entry = _first_file_entry_find(tb); + + if (!entry) return; + evas_object_smart_callback_call(tb->layout, "slideshow", entry); +} + +static void +_flow(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Thumb_Browser *tb = data; + Elm_Gengrid_Item *it = elm_gengrid_selected_item_get(tb->grid); + Ephoto_Entry *entry; + + elm_toolbar_item_selected_set(tb->action.flow, EINA_FALSE); + + if (it) entry = elm_gengrid_item_data_get(it); + else entry = _first_file_entry_find(tb); + + if (!entry) return; + evas_object_smart_callback_call(tb->layout, "flow", entry); +} + +static void +_key_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info) +{ + Ephoto_Thumb_Browser *tb = data; + Evas_Event_Key_Down *ev = event_info; + Eina_Bool alt = evas_key_modifier_is_set(ev->modifiers, "Alt"); + const char *k = ev->keyname; + + if (alt) + { + if (!strcmp(k, "Up")) + { + if (strcmp(tb->ephoto->config->directory, "/") != 0) + { + char *parent = ecore_file_dir_get + (tb->ephoto->config->directory); + if (parent) + ephoto_directory_set(tb->ephoto, parent); + free(parent); + } + } + + return; + } + + if (!strcmp(k, "F5")) + { + Elm_Gengrid_Item *it = elm_gengrid_selected_item_get(tb->grid); + Ephoto_Entry *entry; + if (it) entry = elm_gengrid_item_data_get(it); + else entry = _first_file_entry_find(tb); + + if (entry) + evas_object_smart_callback_call(tb->layout, "slideshow", entry); + } +} + + +static void +_layout_del(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Thumb_Browser *tb = data; + Ecore_Event_Handler *handler; + + _todo_items_free(tb); + _grid_items_free(tb); + EINA_LIST_FREE(tb->handlers, handler) + ecore_event_handler_del(handler); + + if (tb->animator.todo_items) + { + ecore_animator_del(tb->animator.todo_items); + tb->animator.todo_items = NULL; + } + if (tb->ls) + { + tb->layout_deleted = EINA_TRUE; + eio_file_cancel(tb->ls); + return; + } + free(tb); +} + +static Elm_Toolbar_Item * +_toolbar_item_add(Ephoto_Thumb_Browser *tb, const char *icon, const char *label, int priority, Evas_Smart_Cb cb) +{ + Elm_Toolbar_Item *item = elm_toolbar_item_append(tb->toolbar, icon, label, + cb, tb); + elm_toolbar_item_priority_set(item, priority); + return item; +} + +static Eina_Bool +_ephoto_thumb_populate_start(void *data, int type __UNUSED__, void *event __UNUSED__) +{ + Ephoto_Thumb_Browser *tb = data; + + evas_object_smart_callback_call(tb->layout, "changed,directory", NULL); + + _todo_items_free(tb); + _grid_items_free(tb); + elm_gengrid_clear(tb->grid); + elm_fileselector_entry_path_set(tb->fsel, tb->ephoto->config->directory); + + edje_object_signal_emit(tb->edje, "populate,start", "ephoto"); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool -_ephoto_thumb_populate_end(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) +_ephoto_thumb_populate_end(void *data, int type __UNUSED__, void *event __UNUSED__) { - etb->ls = NULL; - + Ephoto_Thumb_Browser *tb = data; + + tb->ls = NULL; + if (tb->layout_deleted) + { + free(tb); + return ECORE_CALLBACK_PASS_ON; + } + + edje_object_signal_emit(tb->edje, "populate,stop", "ephoto"); + return ECORE_CALLBACK_PASS_ON; } static Eina_Bool -_ephoto_thumb_populate_error(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) +_ephoto_thumb_populate_error(void *data, int type __UNUSED__, void *event __UNUSED__) { + Ephoto_Thumb_Browser *tb = data; + + edje_object_signal_emit(tb->edje, "populate,error", "ephoto"); + return ECORE_CALLBACK_PASS_ON; } static Eina_Bool -_ephoto_thumb_entry_create(void *data __UNUSED__, int type __UNUSED__, void *event) +_ephoto_thumb_entry_create(void *data, int type __UNUSED__, void *event) { + Ephoto_Thumb_Browser *tb = data; Ephoto_Event_Entry_Create *ev = event; Ephoto_Entry *e; e = ev->entry; - etb->todo_items = eina_list_append(etb->todo_items, e); + tb->todo_items = eina_list_append(tb->todo_items, e); - if (!etb->animator.todo_items) - etb->animator.todo_items = ecore_animator_add(_todo_items_process, NULL); + if (!tb->animator.todo_items) + tb->animator.todo_items = ecore_animator_add(_todo_items_process, tb); return ECORE_CALLBACK_PASS_ON; } -static Evas_Object * -_ephoto_thumbnail_icon_get(void *data, Evas_Object *obj __UNUSED__, const char *part __UNUSED__) +static void +_ephoto_up_clicked(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) { - Ephoto_Entry *entry = data; - Evas_Object *o; - const char *ext = strrchr(entry->path, '.'); + Ephoto_Thumb_Browser *tb = data; + char *parent_dir; - if (!strncmp(part, "elm.swallow.icon.", sizeof("elm.swallow.icon.") - 1) != 0) - return NULL; + parent_dir = ecore_file_dir_get(tb->ephoto->config->directory); + if (!parent_dir) + return; + ephoto_directory_set(tb->ephoto, parent_dir); +} - if (ext) +Evas_Object * +ephoto_thumb_browser_add(Ephoto *ephoto, Evas_Object *parent) +{ + Evas_Object *layout = elm_layout_add(parent); + Ephoto_Thumb_Browser *tb; + + EINA_SAFETY_ON_NULL_RETURN_VAL(layout, NULL); + + tb = calloc(1, sizeof(Ephoto_Thumb_Browser)); + EINA_SAFETY_ON_NULL_GOTO(tb, error); + tb->ephoto = ephoto; + tb->layout = layout; + tb->edje = elm_layout_edje_get(layout); + evas_object_event_callback_add(layout, EVAS_CALLBACK_DEL, _layout_del, tb); + evas_object_event_callback_add + (layout, EVAS_CALLBACK_KEY_DOWN, _key_down, tb); + evas_object_data_set(layout, "thumb_browser", tb); + + if (!elm_layout_theme_set + (layout, "layout", "application", "toolbar-vbox")) { - if ((!strcasecmp(ext, "jpg")) || (!strcasecmp(ext, "jpeg"))) - ethumb_client_format_set(ephoto->client, ETHUMB_THUMB_JPEG); + ERR("could not load style 'toolbar-vbox' from theme"); + goto error; } - else - ethumb_client_format_set(ephoto->client, ETHUMB_THUMB_FDO); - ethumb_client_size_set(ephoto->client, etb->thumb_size, etb->thumb_size); + tb->toolbar = edje_object_part_external_object_get + (tb->edje, "elm.external.toolbar"); + if (!tb->toolbar) + { + ERR("no toolbar in layout!"); + goto error; + } + elm_toolbar_homogenous_set(tb->toolbar, EINA_FALSE); + elm_toolbar_mode_shrink_set(tb->toolbar, ELM_TOOLBAR_SHRINK_MENU); + elm_toolbar_menu_parent_set(tb->toolbar, parent); - o = elm_thumb_add(ephoto->win); - elm_object_style_set(o, "noframe"); - elm_thumb_file_set(o, entry->path, NULL); - evas_object_show(o); + tb->action.flow = _toolbar_item_add + (tb, "image", "Flow", 120, _flow); + tb->action.slideshow = _toolbar_item_add + (tb, "media-playback-start", "Slideshow", 100, _slideshow); + tb->action.zoom_in = _toolbar_item_add + (tb, "zoom-in", "Zoom In", 50, _zoom_in); + tb->action.zoom_out = _toolbar_item_add + (tb, "zoom-out", "Zoom Out", 50, _zoom_out); + tb->action.view_single = _toolbar_item_add + (tb, "image", "Single", 50, _view_single); - return o; -} - -static char * -_ephoto_thumbnail_label_get(void *data, Evas_Object *obj __UNUSED__, const char *part __UNUSED__) -{ - Ephoto_Entry *e = data; - - return strdup(e->label); -} - -static void -_ephoto_thumbnail_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__) -{ - -} - -static void -_ephoto_change_dir(void *data __UNUSED__, Evas_Object *o __UNUSED__, void *event_info) -{ - const char *path = event_info; - - if (!path) return; - - ephoto_populate(path); -} - -static void -_ephoto_zoom_in(void *data __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) -{ - elm_toolbar_item_selected_set(etb->action.zoom_in, EINA_FALSE); - etb->thumb_size += ZOOM_STEP; - if (etb->thumb_size >= ZOOM_MAX) - etb->thumb_size = ZOOM_MAX; - elm_gengrid_item_size_set(etb->grid, etb->thumb_size, etb->thumb_size); - elm_toolbar_item_disabled_set(etb->action.zoom_in, etb->thumb_size == ZOOM_MAX); - elm_toolbar_item_disabled_set(etb->action.zoom_out, etb->thumb_size == ZOOM_MIN); -} - -static void -_ephoto_zoom_out(void *data __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) -{ - elm_toolbar_item_selected_set(etb->action.zoom_out, EINA_FALSE); - etb->thumb_size -= ZOOM_STEP; - if (etb->thumb_size <= ZOOM_MIN) - etb->thumb_size = ZOOM_MIN; - elm_gengrid_item_size_set(etb->grid, etb->thumb_size, etb->thumb_size); - elm_toolbar_item_disabled_set(etb->action.zoom_out, etb->thumb_size == ZOOM_MIN); - elm_toolbar_item_disabled_set(etb->action.zoom_in, etb->thumb_size == ZOOM_MAX); -} - -static void -_ephoto_show_flow(void *data __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) -{ - Elm_Gengrid_Item *egi; - Ephoto_Entry *entry; - - elm_toolbar_item_selected_set(etb->action.view_flow, EINA_FALSE); - - elm_object_unfocus(etb->grid); - - egi = elm_gengrid_selected_item_get(etb->grid); - if (egi) - entry = elm_gengrid_item_data_get(egi); - else - entry = eina_list_data_get - (eina_list_nth_list(ephoto->entries, 0)); - if (!entry) - return; - - printf("%s\n", entry->path); - ephoto_flow_browser_show(entry); -} - -static void -_ephoto_show_slideshow(void *data __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) -{ - Elm_Gengrid_Item *egi; - Ephoto_Entry *entry; - - elm_toolbar_item_selected_set(etb->action.slideshow, EINA_FALSE); - - elm_object_unfocus(etb->grid); - - egi = elm_gengrid_selected_item_get(etb->grid); - if (egi) - entry = elm_gengrid_item_data_get(egi); - else - entry = eina_list_data_get - (eina_list_nth_list(ephoto->entries, 0)); - if (!entry) - return; - - ephoto_slideshow_show(entry); + tb->fsel = elm_fileselector_entry_add(layout); + EINA_SAFETY_ON_NULL_GOTO(tb->fsel, error); + evas_object_size_hint_weight_set(tb->fsel, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(tb->fsel, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_fileselector_entry_button_label_set(tb->fsel, "Choose..."); + elm_fileselector_entry_folder_only_set(tb->fsel, EINA_TRUE); + evas_object_smart_callback_add + (tb->fsel, "file,chosen", _changed_dir, tb); + evas_object_smart_callback_add + (tb->fsel, "activated", _changed_dir_text, tb); + + evas_object_show(tb->fsel); + elm_layout_box_append(layout, "elm.box.content", tb->fsel); + + tb->overlay = elm_layout_add(layout); + elm_layout_file_set + (tb->overlay, PACKAGE_DATA_DIR "/themes/default/ephoto.edj", + "ephoto,thumb,grid"); + evas_object_size_hint_weight_set + (tb->overlay, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set + (tb->overlay, EVAS_HINT_FILL, EVAS_HINT_FILL); + edje_object_signal_callback_add + (elm_layout_edje_get(tb->overlay), "ephoto.signal.up", "ephoto", + _ephoto_up_clicked, tb); + evas_object_show(tb->overlay); + elm_layout_box_append(tb->layout, "elm.box.content", tb->overlay); + + tb->grid = elm_gengrid_add(tb->overlay); + EINA_SAFETY_ON_NULL_GOTO(tb->grid, error); + elm_gengrid_align_set(tb->grid, 0.5, 0.5); + elm_gengrid_bounce_set(tb->grid, EINA_FALSE, EINA_TRUE); + evas_object_size_hint_align_set + (tb->grid, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_size_hint_weight_set + (tb->grid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_smart_callback_add + (tb->grid, "selected", _ephoto_thumb_selected, tb); + _zoom_set(tb, tb->ephoto->config->thumb_size); + evas_object_show(tb->grid); + elm_layout_content_set + (tb->overlay, "ephoto.swallow.content.thumb", tb->grid); + + tb->handlers = eina_list_append + (tb->handlers, ecore_event_handler_add + (EPHOTO_EVENT_POPULATE_START, _ephoto_thumb_populate_start, tb)); + + tb->handlers = eina_list_append + (tb->handlers, ecore_event_handler_add + (EPHOTO_EVENT_POPULATE_END, _ephoto_thumb_populate_end, tb)); + + tb->handlers = eina_list_append + (tb->handlers, ecore_event_handler_add + (EPHOTO_EVENT_POPULATE_ERROR, _ephoto_thumb_populate_error, tb)); + + tb->handlers = eina_list_append + (tb->handlers, ecore_event_handler_add + (EPHOTO_EVENT_ENTRY_CREATE, _ephoto_thumb_entry_create, tb)); + + return layout; + + error: + evas_object_del(layout); + return NULL; }