From 962910db6bb4694f735b78af80b017a26c6e70e0 Mon Sep 17 00:00:00 2001 From: Stephen Houston Date: Tue, 28 Jun 2011 22:26:16 +0000 Subject: [PATCH] Commit the version of Ephoto that has always been the most working and preferred. I will bugfix this version and release it. Any of thousands of rewrites I love to do will have to come for another version somewhere well done the road. Lets just take this and make it solid and release it. Shout out to cedric, bluebugs, captainigloo, k-s, otavio, and any others who contributed to this version. SVN revision: 60775 --- configure.ac | 1 + data/Makefile.am | 2 +- data/images/Makefile.am | 20 + data/images/back.png | Bin 0 -> 1219 bytes data/images/back_grid.png | Bin 0 -> 2274 bytes data/images/first.png | Bin 0 -> 1298 bytes data/images/folder.png | Bin 0 -> 1502 bytes data/images/forward.png | Bin 0 -> 1211 bytes data/images/grid.png | Bin 0 -> 1111 bytes data/images/last.png | Bin 0 -> 1293 bytes data/images/single.png | Bin 0 -> 1944 bytes data/images/slideshow.png | Bin 0 -> 3447 bytes data/images/up.png | Bin 0 -> 2240 bytes data/images/zoom-fit.png | Bin 0 -> 2080 bytes data/images/zoom-in.png | Bin 0 -> 2206 bytes data/images/zoom-original.png | Bin 0 -> 2164 bytes data/images/zoom-out.png | Bin 0 -> 2127 bytes data/themes/default/ephoto.edc | 693 +++++++++++++---- data/themes/default/images/Makefile.am | 7 + data/themes/default/images/bt_sm_base1.png | Bin 0 -> 477 bytes data/themes/default/images/bt_sm_hilight.png | Bin 0 -> 285 bytes data/themes/default/images/bt_sm_shine.png | Bin 0 -> 275 bytes data/themes/default/images/directory-512.png | Bin 0 -> 22206 bytes .../default/images/directory-up-512.png | Bin 0 -> 35965 bytes src/bin/Makefile.am | 5 +- src/bin/ephoto.c | 2 +- src/bin/ephoto.h | 97 ++- src/bin/ephoto_config.c | 71 +- src/bin/ephoto_directory_thumb.c | 176 +++++ src/bin/ephoto_main.c | 303 ++++---- src/bin/ephoto_single_browser.c | 733 ++++++++++++++---- src/bin/ephoto_slideshow.c | 193 +++++ src/bin/ephoto_thumb_browser.c | 410 ++++++++-- 33 files changed, 2119 insertions(+), 594 deletions(-) create mode 100644 data/images/Makefile.am create mode 100644 data/images/back.png create mode 100644 data/images/back_grid.png create mode 100644 data/images/first.png create mode 100644 data/images/folder.png create mode 100644 data/images/forward.png create mode 100644 data/images/grid.png create mode 100644 data/images/last.png create mode 100644 data/images/single.png create mode 100644 data/images/slideshow.png create mode 100644 data/images/up.png create mode 100644 data/images/zoom-fit.png create mode 100644 data/images/zoom-in.png create mode 100644 data/images/zoom-original.png create mode 100644 data/images/zoom-out.png create mode 100644 data/themes/default/images/bt_sm_base1.png create mode 100644 data/themes/default/images/bt_sm_hilight.png create mode 100644 data/themes/default/images/bt_sm_shine.png create mode 100644 data/themes/default/images/directory-512.png create mode 100644 data/themes/default/images/directory-up-512.png create mode 100644 src/bin/ephoto_directory_thumb.c create mode 100644 src/bin/ephoto_slideshow.c diff --git a/configure.ac b/configure.ac index c15d108..b1d5641 100644 --- a/configure.ac +++ b/configure.ac @@ -164,6 +164,7 @@ Makefile ephoto.spec data/Makefile data/desktop/Makefile +data/images/Makefile data/themes/Makefile data/themes/default/Makefile data/themes/default/images/Makefile diff --git a/data/Makefile.am b/data/Makefile.am index c37a4b6..b9e3741 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -1,2 +1,2 @@ MAINTAINERCLEANFILES = Makefile.in Makefile -SUBDIRS = themes desktop +SUBDIRS = desktop images themes diff --git a/data/images/Makefile.am b/data/images/Makefile.am new file mode 100644 index 0000000..f1dbc96 --- /dev/null +++ b/data/images/Makefile.am @@ -0,0 +1,20 @@ +MAINTAINERCLEANFILES = Makefile.in Makefile + +IMAGES = \ +back.png \ +back_grid.png \ +first.png \ +folder.png \ +forward.png \ +grid.png \ +last.png \ +single.png \ +slideshow.png \ +up.png \ +zoom-fit.png \ +zoom-in.png \ +zoom-original.png \ +zoom-out.png + +imagesdir = $(pkgdatadir)/images +images_DATA = $(IMAGES) diff --git a/data/images/back.png b/data/images/back.png new file mode 100644 index 0000000000000000000000000000000000000000..964d853ff2fb3882efbed59f469514ab4c9a462f GIT binary patch literal 1219 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 literal 0 HcmV?d00001 diff --git a/data/images/first.png b/data/images/first.png new file mode 100644 index 0000000000000000000000000000000000000000..0c99ca1c05b077f5b056ac39e83241737abbc693 GIT binary patch literal 1298 zcmV+t1?~EYP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00!&;00!&<9(6c100007bV*G`2ipc1 z4-pBEnGh8K00fdrL_t(&-sM_NNGn$q{?5IVyu?<0Vy)E|#b+$d(+bvy@^JBRBX1}8 zhlscmLob#RY-8&&>Mn0QBo||GnAtDLD1Hhew&Y1w>0AkE+Brzvah=^VQD3wya zC8B0#ew9n;iRf=;{>?Cq9RR1ytR^F1z4;O;F7f;O&XNzP{H}Q&aDXi;KU|H0{O! zkH;eq4-b3qn#AYx{g{SdbRQ1f8G)jrqJpKRrS|6L=2!7}oK*Gm9Mv>UWJ=O(R-w;1 zASWg!>PJUMe~?moQi%TO4cJixQd6j=rsn0s!a}>>@Bca$i{UvILyD75Y>&Y7^z`>V zJw0{0uDinF@UwMdM*vPZfcOrI2MY0NVEUc64`l_h@Kn zsG+m7v$CkDh@Luy=$;NFx@JgK)%fD#Vt8|NvwC!NG|M%ur@VC=_~>2ndHM zlxivf?cm@bIypJ{Pghsho8I2u>eA9uX&)4gMvd<7?w`|b0X<3|$UqC304|wXU0q$h z+}heY8Xg{g)7siv;&Qp{bDROVOrwPycj9a~kQ@r&{N&^$HZwDG+TPy&U4MUnO+`h8 z+ZIJF+Y6es95_EecQQ8vhyu_yHZ~$VJ3B{%gM;-gEiEP4Br!2Fh{y-v1Ax{$9xBGw zo@By4Ia!h6YRkSj5C~N7@9+N!;QRp&{0iVFW&T{QUb~-i zjdfiIGjlv1*Hu-Ox~@k6d`zfPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L00!&;00!&<9(6c100007bV*G`2ipc1 z4-N=5#4a5G00mx2L_t(&-ql)7XdGo2e%{$lVrrUb6Oyhi)M`8i6v0ctlOBQ|JcxpL z^&oihP!&N+K?M=&LA`hoDk_TTsc01~Duf~8*c-p9lDeKX(e z&ZIeHXSM^AWOtL9_xaxEd7t~ll0I$@`8Tej*5h@=h0Mw$`tFc^-9Z4O+l}kx&1UW9S8vuaF?!b{AH4qDqwDLN)x8XS zOA(%U_oGD-*#OW?%Wzr-#sNHZ{>zuX-fS%I>PDr3VGNH|0NMN1-`L{HFAEpnc>c9h zp8#0t1d)~j0T8S=YS>s?-Q{gov37l_H)XOkFn-U}_%Q(A184zgWC9S8zygrv|8AgF zTj`5ZdHbDG0dNq&zar8isa+Hjk<#q!15@uDf8o`GQ3wa~>&sWG zOP{}Z;=MQL=g(Iim4qZjqy%8<^rvsX_2A6C&u-SM2)A2+xZov8u--=`4B#qBbxu40;K20JLvzjLMYOjX9)1A@fQUKK2_(ZA8R3gzWgATQg@>;0f6H zfVvDwN)>9uYqibqkVy^Xxs616Uf?p&&K9xZ8NK=+SW_p8;1CmDU}MWLG65jU5XunZ zG~!mjAPvwHGOZ3YE~6DGXF4lF2S2i5C= z91u?fT^R_N&_K{p8Vcc1><2Cjs=M)lp$QFG zx`?FAtU1DPyCfFCPTi=Oky4}XQxdHN3o4_Yp~Y=Yst+J!2%$I93FCgKu)}XD2t}Bv zhvnqHMwl4fXCZyda2w$pGLh*n$#eQ|hN5D9h? zalD0>;C@j+6569TCui(R0A}`#hcC&0h}p3-jhcim00f{{s%y2w6T@S!|L^2}F-Df0 zk^iYSYu3#Y)BOg3`k8Z!7bGw`2X~EM zL!&0{^3v+sH}e-SfAPbgX8~NYF(;mpO#+w!a6f>%?H+tT9W?-d1NaTV0?BKg00J9y z#eN^^GXR?w#1ep-ds3P9pt}U~%&g!3lSKh+cRuL;AHG-oNo9w|p8x;=07*qoM6N<$ Eg0M@Z+yDRo literal 0 HcmV?d00001 diff --git a/data/images/forward.png b/data/images/forward.png new file mode 100644 index 0000000000000000000000000000000000000000..3e4516c24f0daa91a9b12ee8e4ba5b221394328e GIT binary patch literal 1211 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 W|4y*XT-pcB^$eb_elF{r5}E)h5BWR* literal 0 HcmV?d00001 diff --git a/data/images/last.png b/data/images/last.png new file mode 100644 index 0000000000000000000000000000000000000000..78825d832d45f1ecc4b47dca384b19b3058daf54 GIT binary patch literal 1293 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 Z{6A@(2k2zAsFVNz002ovPDHLkV1j%gXO{o~ literal 0 HcmV?d00001 diff --git a/data/images/up.png b/data/images/up.png new file mode 100644 index 0000000000000000000000000000000000000000..9d1cbe46464568e958c228d4065a5c50f725fe6c GIT binary patch literal 2240 zcmV;x2tW6UP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00!&;00!&<9(6c100007bV*G`2ipc1 z4+|ob2osI~00=-yL_t(&-qo64h+KCS$3N$HXLhsgX47Oh+3aq*Nw%@2&=iA^m!NsE z4?#g6q=8}#Sdt+O%}D$tKzV zJ9Fp$&hg>??wvccclHltV>XOdek*3i`}yT~pT8<)4@IN`^Z;FJ z*dqp(%q+Ph3<$~({qfh&KKp^ayFTfhtE{xa!s629AD?;QVaV{1VtsyUO@g9o4?SCkKyLl% z*J8W=my4Ia@wu;^`6+O{-H0*|2;i3HXQ<6huTji2b2lb7CQU}w{;|RSr-0uBi@;&Eukwr7pWg#RY(V;^J2EY6D&!65oICQkPuWul8 zi2R=vx5B^kv$IoICMSOJrKi9D&GYA9oy%nT8UfWa4j_U&(dX#ahmuFp>58;c;B z^3ob$8?SZ#!O}EDRK1JtzCr$aas2s@KlapDfGcLEStYIl+xG1pIkGS{P7==->=#S` zk#w=aE66cPWoL#Y@jMGt*=dO;&nrvkR5&{ za)?O53zEK@(c5MHzz*PDpjIj5{w?Mk`8I;(sx}%4Z~o^Bzx(q)cxU1|vOyM@!M#KM zJo4d(xPR|Xs+CHvOBzf@sv}$4J&;vAFe|t&J%Op43!FW7fvFpF^lYkbC%~cWu%@XMnkFAtS_e#(G%ID68fFm34V(zKqjxY2Cqf)IQpK~#2pBNcQV%%5VIE8a z3&Fl*+b_EiM# z$mkex9OJ#mdrut4jEs&kI`&|J-E>$6ra@*24m8b78SQTau_jGR3l^(sUdlTI)- z$4@>-5Bw1#FsMU8xd)An?TZD$ zj36_sz)c`4zGX&OX+@wf^uu5#sYkQ`yp3+`v+}GK(x@wwUFrds8d-Ezn)1$qRn}<2&Re?qgrt^l4QeY)rL{6RB&Q}O1NBk!$@xcI)b=4 z!V6^;F=Ke3m%qO`Nu^RHiYhoKhzKGM=Nuvqae{MEcrG~STE;5*l%b_TD)!%os^NWt zpbQW6A}w>E=A^n)ArlBaurvYX1a=Sha`?b5E?m0C^jxi-lCKEJg6K8%)BT$_@$kOw z>>ljJi8YH@mRMXl1`N>4lXEk>270z&(vtVPyCNRCZ-D#n-HKP;&=888qpK@QYeumc zhD`L%z$y2F$+n%J>^6KJoBD3jiwmCUVfTDGEjKHr&qS6T&9z73X;AmGL)# z*`RZ7z#{P0&wu;c%iil}tCKE+{<|-n;KG1M0zu31B9>sVuwbj>4VUo%WY33N+d;y8j0t_dZG5qsfB+ O0000Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00!&;00!&<9(6c100007bV*G`2ipc1 z4-69ekhSFi00*E+L_t(&-rZVTOjBDL{?=OE(3?~&7sV)!o-l%l6=lYeoaE?u&Y8@K zV}klXqK_sLg$I52!9-DFjHnO#VB(XeiSc2Q8761+!5|jW0Zl88U@|f|GF*nz?iSkJ zz1LdvaCRFY47P=%Fn_YsbYH)3egAE(y@`|(tJx@4xmjlaA%rjhRseY`kemRJ1dxzY z@-*g@3lT!{0k|1sdk7)5Qp$}h2|Xd?qm;6bbKVPJQc9_%6);D>kTJGTO8GtK8~|2Y zaFkI>%NSz{=llgBWI{^GQ*L4dP%NeN2q9LizY8HCrSt$OHZiCDTmeu7pmY_)ZK;V> znN5HJu&<)zV>dCU2@rEzEtbane^m!^B|`zQ&6_vd8yg$TtE;Qmy?ps{^1*`#!=t04 zaRBwd2tX{A8n_athmAG84JSim+LV!{VN~sKmLYm+2 zA8l-G?9_E#GmFvEkW&gF#Ge58q?8kMo?m6G+=&w>ei;Y^j_upGZQN-hMVz=9^2M!$A(%;{I^w_au+fsqIOffJ=ff4}ql+xd2pn&DhojYGQG&FoA zgdn=Eqr1C1=JWZ&{r&ywz`%f7Sy@?7U0vMMf#&As7XXYU zD)1KoT~f+%OSab^IdbF|hYug#W*7z;8yn;8?d|`(fB*hl0MjNgF*G#9IyyQSA;j6# z)Kt~f)U?U%cGHH2hKgs;o{c?v^yuAkxYK+EzNVCZx0nL?`T5SSuC70nmX}DS!CzVXf2Yq^hbW>g((O7!HTSOHklP0G(3G@oX}W z<=VAtzb+~&a_YK{_V)Infq{V`08tdWo35GIeL40L#EsC3?FD1hN1TL^@TX+*t&IVL1}5JGneXbVk8R{uf=Xg z>+0&IieNApS(esfmQO84hD#}p!NI|psX&ppP_V)c*#E^3H=FNJW z&6dwOhtKC5Gi!ugY7l2r$dX>K_wPMDJrT}1_UzfS>C~xHJ2D_)Ie-4Vr@FejOb7wP zF!1#0(+@dhu}`|trxY*%MBCch0+W-IT+=ji_UzeTdA;863knMC3k(J=E-o&3{P^(? zCr_T-t!WxK=TKGE7#|;xWKlyFosp$_p)vr60Muu2VZot8hiaOen=9OIH)D)JQIzEP z_;}>~`}b3C-n-1#%1@52D9F#xho)(%JP%#hp{lBwn3zaz+_=%Y zX3ZKn91ijJ?c0%-mX_zCP$-&1EW9uYe4I_-I{^E#a6N~`Vkta$@Zh$(x;l4FO^wTL zw=;904B>EC4+ev(-|zoVXJ_X}UDuQA*ROZox^-)>+wE2?77Hk)@usGxC&6HFG)ofQ z0DfEwfpmjsE-+aYMRBZKx6aNOBZLq#GBOgCQpU_|lQ46>?dZ{?drzM}{S_f3rCQ?5 znKMsbzkdDiEJ!RHfmB?uS=;QO7xVnwLI`nRym;}Oy1F`7ibP&sUZSO?<*!*NktUGq zoOpiUZ-7cA%s9Y9=Be`IlSm{cu3o+B>+S7LE1_wct+KLm!~Ysk6XSv|^d)RY z)3k}Uwl-f^SJ#xPs(AkV`BWef2xl4xsVuY!!0#DjdpPG`;>Cs?z*?u%>59c-5p$s+ zzF-w)jF@j}{w$^ZV9BtZ{@IlPkc`D*A+tx)Gl&6_)s*rxn2}3w^d*Bh=cUD5RwY)N zEl5C6O7&HsfIfRJog$zCh;Yv1R;!gV##Wpfj4@)hS}Er|4j^J;P6zP}fFZ*$wi7}M zZ8n>cmzQTDgb<6x0zwF3j1fvH7-PijI5B&lc~1J=)NugdoJ%QX>Q{2kVg5=X#GK>v z_DRDqAf=SaWYW+yjTwe917OI+oUQ`|KfS)(0l))b3jo&&6Cq*(e+8f)z?hU$&i>SZ z0w@Hq-UOew!U!Zy5~Bd7q?979z?|?V#A3SEO8nTvkW$X675@dj)WPG|l>QX}0000< KMNUMnLSTZ%v*p(S literal 0 HcmV?d00001 diff --git a/data/images/zoom-in.png b/data/images/zoom-in.png new file mode 100644 index 0000000000000000000000000000000000000000..dc53d9ed186c41a91fc0f0fee1a66cf88c9a0540 GIT binary patch literal 2206 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 literal 0 HcmV?d00001 diff --git a/data/images/zoom-original.png b/data/images/zoom-original.png new file mode 100644 index 0000000000000000000000000000000000000000..de57e903785f5b715e4c191f9f24bcb3606f4f41 GIT binary patch literal 2164 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 a_b>!XDC}*jKQ{~LDh5wiKbLh*2~7Y831e~q literal 0 HcmV?d00001 diff --git a/data/themes/default/images/bt_sm_shine.png b/data/themes/default/images/bt_sm_shine.png new file mode 100644 index 0000000000000000000000000000000000000000..23bf3110e10797618b2b3ec49c3678405a8c9bd9 GIT binary patch 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 literal 0 HcmV?d00001 diff --git a/data/themes/default/images/directory-512.png b/data/themes/default/images/directory-512.png new file mode 100644 index 0000000000000000000000000000000000000000..7beeb3d5fe99dae6817ace2527fc868c92dcbae6 GIT binary patch literal 22206 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%0A!UfrA2=kEHE!#dJsj;h$ukUw0QU=Z3@ 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 + info->name_start; if (bname[0] == '.') return EINA_FALSE; @@ -185,23 +182,17 @@ _ephoto_eina_file_direct_info_image_useful(const Eina_File_Direct_Info *info) ext++; if ((strcasecmp(ext, "jpg") == 0) || (strcasecmp(ext, "jpeg") == 0) || - (strcasecmp(ext, "png") == 0) || - (strcasecmp(ext, "svg") == 0) || - (strcasecmp(ext, "svgz") == 0) || - (strcasecmp(ext, "bmp") == 0) || - (strcasecmp(ext, "dib") == 0) || - (strcasecmp(ext, "tiff") == 0) || - (strcasecmp(ext, "tif") == 0) || - (strcasecmp(ext, "psd") == 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 Event Handlers*/ -extern int EPHOTO_EVENT_ENTRY_CREATE_DIR; -extern int EPHOTO_EVENT_ENTRY_CREATE_THUMB; +extern int EPHOTO_EVENT_ENTRY_CREATE; extern int EPHOTO_EVENT_POPULATE_START; extern int EPHOTO_EVENT_POPULATE_END; extern int EPHOTO_EVENT_POPULATE_ERROR; diff --git a/src/bin/ephoto_config.c b/src/bin/ephoto_config.c index 3eb5db4..602e2f3 100644 --- a/src/bin/ephoto_config.c +++ b/src/bin/ephoto_config.c @@ -1,6 +1,6 @@ #include "ephoto.h" -#define CONFIG_VERSION 6 +#define CONFIG_VERSION 5 static int _ephoto_config_load(Ephoto *ephoto); static Eina_Bool _ephoto_on_config_save(void *data); @@ -13,42 +13,52 @@ 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))) + 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); - EET_DATA_DESCRIPTOR_ADD_BASIC - (edd, Ephoto_Config, "config_version", config_version, EET_T_INT); - EET_DATA_DESCRIPTOR_ADD_BASIC - (edd, Ephoto_Config, "autohide_toolbar", autohide_toolbar, EET_T_INT); - EET_DATA_DESCRIPTOR_ADD_BASIC - (edd, Ephoto_Config, "best_fit_images", best_fit_images, EET_T_INT); - EET_DATA_DESCRIPTOR_ADD_BASIC - (edd, Ephoto_Config, "thumb_gen_size", thumb_gen_size, EET_T_INT); - EET_DATA_DESCRIPTOR_ADD_BASIC - (edd, Ephoto_Config, "thumb_size", thumb_size, EET_T_INT); - EET_DATA_DESCRIPTOR_ADD_BASIC - (edd, Ephoto_Config, "slideshow_timeout", slideshow_timeout, EET_T_INT); - EET_DATA_DESCRIPTOR_ADD_BASIC - (edd, Ephoto_Config, "directory", directory, EET_T_STRING); - EET_DATA_DESCRIPTOR_ADD_BASIC - (edd, Ephoto_Config, "slideshow_transition", slideshow_transition, EET_T_STRING); +#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->autohide_toolbar = 0; - ephoto->config->best_fit_images = 0; - ephoto->config->thumb_gen_size = 256; 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: @@ -102,25 +112,16 @@ _ephoto_config_load(Ephoto *ephoto) ephoto->config = eet_data_read(ef, edd, "config"); eet_close(ef); - if (!ephoto->config) - { - DBG("Warning! No configuration found! Writing a new" - "default configuration!\n"); - return 0; - } - else if (ephoto->config->config_version > CONFIG_VERSION) + if (ephoto->config->config_version > CONFIG_VERSION) { ephoto_config_free(ephoto); ephoto->config = calloc(1, sizeof(Ephoto_Config)); return 0; } - else 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; } diff --git a/src/bin/ephoto_directory_thumb.c b/src/bin/ephoto_directory_thumb.c new file mode 100644 index 0000000..eeda248 --- /dev/null +++ b/src/bin/ephoto_directory_thumb.c @@ -0,0 +1,176 @@ +#include "ephoto.h" + +typedef struct _Ephoto_Directory_Thumb Ephoto_Directory_Thumb; +struct _Ephoto_Directory_Thumb +{ + Eio_File *ls; + Eina_List *objs; + Ephoto_Entry *entry; + Eina_Bool canceled:1; +}; + +static Eina_Hash *_pending_dirs = NULL; + +static void +_entry_free(void *data, const Ephoto_Entry *entry __UNUSED__) +{ + Ephoto_Directory_Thumb *dt = data; + dt->entry = NULL; +} + +static void +_ephoto_directory_thumb_free(Ephoto_Directory_Thumb *dt) +{ + if (dt->entry) + { + ephoto_entry_free_listener_del(dt->entry, _entry_free, dt); + eina_hash_del(_pending_dirs, dt->entry->path, dt); + dt->entry = NULL; + } + + if (dt->ls) + { + dt->canceled = EINA_TRUE; + eio_file_cancel(dt->ls); + return; + } + + free(dt); + + if (_pending_dirs) + { + if (!eina_hash_population(_pending_dirs)) + { + eina_hash_free(_pending_dirs); + _pending_dirs = NULL; + } + } +} + +static void +_obj_del(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) +{ + Ephoto_Directory_Thumb *dt = data; + dt->objs = eina_list_remove(dt->objs, obj); + if (!dt->objs) + { + dt->canceled = EINA_TRUE; + _ephoto_directory_thumb_free(dt); + } +} + +static Eina_Bool +_populate_filter(void *data __UNUSED__, Eio_File *handler __UNUSED__, const Eina_File_Direct_Info *info) +{ + return _ephoto_eina_file_direct_info_image_useful(info); +} + +static void +_populate_end(void *data, Eio_File *handler __UNUSED__) +{ + Ephoto_Directory_Thumb *dt = data; + Evas_Object *obj; + dt->ls = NULL; + + EINA_LIST_FREE(dt->objs, obj) + evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL, _obj_del, dt); + + if (dt->entry) + { + dt->entry->dir_files_checked = EINA_TRUE; + if ((dt->entry->item) && (!dt->canceled)) + elm_gengrid_item_update(dt->entry->item); + } + + _ephoto_directory_thumb_free(dt); +} + +static void +_populate_error(void *data, Eio_File *handler, int error) +{ + Ephoto_Directory_Thumb *dt = data; + if (error) ERR("could not populate: %s", strerror(error)); + _populate_end(dt, handler); +} + +static void +_populate_main(void *data, Eio_File *handler __UNUSED__, const Eina_File_Direct_Info *info) +{ + Ephoto_Directory_Thumb *dt = data; + Evas_Object *obj; + const char *file; + + if (!dt->objs) return; + if (!dt->entry) return; + + obj = dt->objs->data; + file = eina_stringshare_add(info->path); + + DBG("populate thumbnail %p with path '%s'", obj, file); + + dt->objs = eina_list_remove_list(dt->objs, dt->objs); + dt->entry->dir_files = eina_list_append(dt->entry->dir_files, file); + ephoto_thumb_path_set(obj, file); + + evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL, _obj_del, dt); + if ((!dt->objs) && (dt->ls)) + { + eio_file_cancel(dt->ls); + dt->ls = NULL; + } +} + +Evas_Object * +ephoto_directory_thumb_add(Evas_Object *parent, Ephoto_Entry *entry) +{ + Ephoto_Directory_Thumb *dt; + Evas_Object *obj; + + if (_pending_dirs) + dt = eina_hash_find(_pending_dirs, entry->path); + else + { + dt = NULL; + _pending_dirs = eina_hash_stringshared_new(NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(_pending_dirs, NULL); + } + + obj = ephoto_thumb_add(entry->ephoto, parent, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL); + + if (!dt) + { + dt = calloc(1, sizeof(Ephoto_Directory_Thumb)); + if (!dt) + { + ERR("could not allocate memory for Ephoto_Directory_Thumb"); + evas_object_del(obj); + return NULL; + } + ephoto_entry_free_listener_add(entry, _entry_free, dt); + dt->entry = entry; + dt->ls = eio_file_direct_ls(entry->path, + _populate_filter, + _populate_main, + _populate_end, + _populate_error, + dt); + if (!dt->ls) + { + ERR("could not create eio_file_direct_ls(%s)", entry->path); + evas_object_del(obj); + free(dt); + return NULL; + } + + eina_hash_add(_pending_dirs, entry->path, dt); + DBG("start thread to lookup inside '%s' for thumbnails.", entry->path); + } + else + DBG("thread already started, wait for thumbnails in '%s'", entry->path); + + dt->objs = eina_list_append(dt->objs, obj); + + evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _obj_del, dt); + return obj; +} diff --git a/src/bin/ephoto_main.c b/src/bin/ephoto_main.c index 2d9c7e5..368c3d5 100644 --- a/src/bin/ephoto_main.c +++ b/src/bin/ephoto_main.c @@ -1,7 +1,6 @@ #include "ephoto.h" -int EPHOTO_EVENT_ENTRY_CREATE_DIR = 0; -int EPHOTO_EVENT_ENTRY_CREATE_THUMB = 0; +int EPHOTO_EVENT_ENTRY_CREATE = 0; int EPHOTO_EVENT_POPULATE_START = 0; int EPHOTO_EVENT_POPULATE_END = 0; int EPHOTO_EVENT_POPULATE_ERROR = 0; @@ -21,18 +20,93 @@ _ephoto_state_set(Ephoto *ephoto, Ephoto_State state) } static void -_back_clicked(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) +_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_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); +} - switch (ephoto->state) +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_promote_thumb_browser(ephoto); break; - case EPHOTO_STATE_THUMB : ephoto_promote_list_browser(ephoto); break; - case EPHOTO_STATE_LIST : break; - default : break; + 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); } - ephoto_title_set(ephoto, ephoto->config->directory); + 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_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_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 @@ -48,13 +122,10 @@ ephoto_window_add(const char *path) { Ephoto *ephoto = calloc(1, sizeof(Ephoto)); Ethumb_Client *client = elm_thumb_ethumb_client_get(); - Evas_Object *o; char buf[PATH_MAX]; - int w, h; EINA_SAFETY_ON_NULL_RETURN_VAL(ephoto, NULL); - EPHOTO_EVENT_ENTRY_CREATE_DIR = ecore_event_type_new(); - EPHOTO_EVENT_ENTRY_CREATE_THUMB = ecore_event_type_new(); + 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(); @@ -76,6 +147,7 @@ ephoto_window_add(const char *path) 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)) @@ -91,72 +163,14 @@ ephoto_window_add(const char *path) elm_win_resize_object_add(ephoto->win, ephoto->bg); evas_object_show(ephoto->bg); - ephoto->overlay = elm_bg_add(ephoto->bg); - evas_object_size_hint_weight_set - (ephoto->overlay, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_size_hint_fill_set(ephoto->overlay, EVAS_HINT_FILL, EVAS_HINT_FILL); - elm_bg_color_set(ephoto->overlay, 0, 0, 0); - - elm_win_resize_object_add(ephoto->win, ephoto->bg); - evas_object_show(ephoto->bg); - - ephoto->layout = elm_layout_add(ephoto->win); - if (!ephoto->layout) - { - evas_object_del(ephoto->win); - return NULL; - } - if (!elm_layout_theme_set - (ephoto->layout, "layout", "application", "content-back")) - { - ERR("Content-back"); - evas_object_del(ephoto->win); - return NULL; - } - evas_object_size_hint_weight_set - (ephoto->layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_size_hint_fill_set(ephoto->layout, EVAS_HINT_FILL, EVAS_HINT_FILL); - elm_win_resize_object_add(ephoto->win, ephoto->layout); - ephoto->edje = elm_layout_edje_get(ephoto->layout); - edje_object_signal_callback_add(ephoto->edje, "elm,action,back", "", - _back_clicked, ephoto); - evas_object_show(ephoto->layout); - - o = edje_object_part_external_object_get(ephoto->edje, "back"); - evas_object_geometry_get(o, 0, 0, &w, &h); - ephoto->pager = elm_pager_add(ephoto->win); 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 (ephoto->pager, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_win_resize_object_add(ephoto->win, ephoto->pager); evas_object_show(ephoto->pager); - elm_layout_content_set(ephoto->layout, "elm.swallow.content", ephoto->pager); - - ephoto->help_but = elm_button_add(ephoto->win); - o = elm_icon_add(ephoto->help_but); - elm_icon_standard_set(o, "help-browser"); - evas_object_size_hint_aspect_set(o, EVAS_ASPECT_CONTROL_BOTH, 1, 1); - elm_button_icon_set(ephoto->help_but, o); - evas_object_size_hint_weight_set - (ephoto->help_but, 0.0, 0.0); - evas_object_size_hint_fill_set - (ephoto->help_but, 0.0, 0.0); - evas_object_size_hint_min_set(ephoto->help_but, w, h); - evas_object_size_hint_max_set(ephoto->help_but, w, h); - evas_object_show(ephoto->help_but); - elm_layout_content_set(ephoto->layout, "elm.swallow.end", ephoto->help_but); - - - ephoto->list_browser = ephoto_list_browser_add(ephoto, ephoto->pager); - if (!ephoto->list_browser) - { - ERR("could not add list browser"); - evas_object_del(ephoto->win); - return NULL; - } - elm_pager_content_push(ephoto->pager, ephoto->list_browser); ephoto->thumb_browser = ephoto_thumb_browser_add(ephoto, ephoto->pager); if (!ephoto->thumb_browser) @@ -166,6 +180,14 @@ ephoto_window_add(const char *path) 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, "changed,directory", + _ephoto_thumb_browser_changed_directory, ephoto); + evas_object_smart_callback_add + (ephoto->thumb_browser, "slideshow", + _ephoto_thumb_browser_slideshow, ephoto); ephoto->single_browser = ephoto_single_browser_add(ephoto, ephoto->pager); if (!ephoto->single_browser) @@ -175,12 +197,26 @@ ephoto_window_add(const char *path) 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 single browser"); + 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 p[PATH_MAX]; - snprintf(p, PATH_MAX, "%s/.e/e/fileman/favorites", getenv("HOME")); - path = p; + path = ephoto->config->directory; if ((path) && (!ecore_file_exists(path))) path = NULL; if (!path) { @@ -193,20 +229,22 @@ ephoto_window_add(const char *path) if (ecore_file_is_dir(path)) { - ephoto_promote_list_browser(ephoto); ephoto_directory_set(ephoto, path); + _ephoto_thumb_browser_show(ephoto, NULL); } else { - ephoto_single_browser_path_pending_set(ephoto->single_browser, path); - ephoto_promote_single_browser(ephoto, NULL); char *dir = ecore_file_dir_get(path); 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, 800, 600); + evas_object_resize(ephoto->win, 900, 600); evas_object_show(ephoto->win); return ephoto->win; @@ -217,56 +255,20 @@ ephoto_title_set(Ephoto *ephoto, const char *title) { char buf[1024] = "Ephoto"; - if (title) snprintf(buf, sizeof(buf), "Ephoto - %s", title); + if (title) snprintf(buf, sizeof(buf), "%s - Ephoto", title); elm_win_title_set(ephoto->win, buf); - edje_object_part_text_set(ephoto->edje, "elm.text.title", title); -} - -void -ephoto_promote_list_browser(Ephoto *ephoto) -{ - elm_pager_content_promote(ephoto->pager, ephoto->list_browser); - edje_object_signal_emit(ephoto->edje, "elm,back,hide", "elm"); - _ephoto_state_set(ephoto, EPHOTO_STATE_LIST); -} - -void -ephoto_promote_thumb_browser(Ephoto *ephoto) -{ - if (elm_bg_overlay_get(ephoto->bg)) - { - evas_object_hide(ephoto->overlay); - elm_bg_overlay_unset(ephoto->bg); - } - elm_pager_content_promote(ephoto->pager, ephoto->thumb_browser); - edje_object_signal_emit(ephoto->edje, "elm,back,show", "elm"); - _ephoto_state_set(ephoto, EPHOTO_STATE_THUMB); -} - -void -ephoto_promote_single_browser(Ephoto *ephoto, Ephoto_Entry *e) -{ - elm_pager_content_promote(ephoto->pager, ephoto->single_browser); - elm_bg_overlay_set(ephoto->bg, ephoto->overlay); - if (e) - ephoto_single_browser_entry_set(ephoto->single_browser, e); - _ephoto_state_set(ephoto, EPHOTO_STATE_SINGLE); } static int _entry_cmp(const void *pa, const void *pb) { const Ephoto_Entry *a = pa, *b = pb; - int ret, s; - - s = strcmp(a->basename, b->basename); - if (s > 0) - ret = 1; - else if (s < 0) - ret = -1; + if (a->is_dir == b->is_dir) + return strcoll(a->basename, b->basename); + else if (a->is_dir) + return -1; else - ret = 0; - return ret; + return 1; } static void @@ -277,19 +279,30 @@ _ephoto_populate_main(void *data, Eio_File *handler __UNUSED__, const Eina_File_ Ephoto_Event_Entry_Create *ev; e = ephoto_entry_new(ephoto, info->path, info->path + info->name_start); - + if (info->type == EINA_FILE_DIR) e->is_dir = EINA_TRUE; + else if (info->type == EINA_FILE_REG) e->is_dir = EINA_FALSE; + else e->is_dir = !_ephoto_eina_file_direct_info_image_useful(info); + + if (!ephoto->entries) + ephoto->entries = eina_list_append(ephoto->entries, e); + else + { + int near_cmp; + Eina_List *near_node = eina_list_search_sorted_near_list + (ephoto->entries, _entry_cmp, e, &near_cmp); + + if (near_cmp < 0) + ephoto->entries = eina_list_append_relative_list + (ephoto->entries, e, near_node); + else + ephoto->entries = eina_list_prepend_relative_list + (ephoto->entries, e, near_node); + } + ev = calloc(1, sizeof(Ephoto_Event_Entry_Create)); ev->entry = e; - if (ecore_file_is_dir(info->path)) - ecore_event_add(EPHOTO_EVENT_ENTRY_CREATE_DIR, ev, NULL, NULL); - else - { - ephoto->entries = eina_list_sorted_insert(ephoto->entries, _entry_cmp, e); - ecore_event_add(EPHOTO_EVENT_ENTRY_CREATE_THUMB, ev, NULL, NULL); - if (ephoto->state == EPHOTO_STATE_LIST) - ephoto_promote_thumb_browser(ephoto); - } + ecore_event_add(EPHOTO_EVENT_ENTRY_CREATE, ev, NULL, NULL); } static Eina_Bool @@ -298,11 +311,9 @@ _ephoto_populate_filter(void *data __UNUSED__, Eio_File *handler __UNUSED__, con const char *bname = info->path + info->name_start; if (bname[0] == '.') return EINA_FALSE; + if (info->type == EINA_FILE_DIR) return EINA_TRUE; - if (ecore_file_is_dir(info->path)) - return EINA_TRUE; - else - return _ephoto_eina_file_direct_info_image_useful(info); + return _ephoto_eina_file_direct_info_image_useful(info); } static void @@ -356,7 +367,7 @@ ephoto_directory_set(Ephoto *ephoto, const char *path) { EINA_SAFETY_ON_NULL_RETURN(ephoto); - ephoto_title_set(ephoto, basename(path)); + 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); @@ -461,23 +472,6 @@ ephoto_thumb_path_set(Evas_Object *o, const char *path) elm_thumb_file_set(o, path, NULL); } -Evas_Object * -ephoto_list_icon_add(Ephoto *ephoto, Evas_Object *parent, const char *standard) -{ - Evas_Object *o; - - EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL); - - o = elm_icon_add(parent); - if (!o) return NULL; - - if (standard) elm_icon_standard_set(o, standard); - evas_object_size_hint_aspect_set(o, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1); - ephoto->dirs = eina_list_append(ephoto->dirs, o); - - return o; -} - Ephoto_Entry * ephoto_entry_new(Ephoto *ephoto, const char *path, const char *label) { @@ -495,6 +489,7 @@ ephoto_entry_new(Ephoto *ephoto, const char *path, const char *label) void ephoto_entry_free(Ephoto_Entry *entry) { + const char *s; Ephoto_Entry_Free_Listener *fl; EINA_LIST_FREE(entry->free_listeners, fl) @@ -505,6 +500,7 @@ ephoto_entry_free(Ephoto_Entry *entry) EINA_SAFETY_ON_NULL_RETURN(entry); eina_stringshare_del(entry->path); eina_stringshare_del(entry->label); + EINA_LIST_FREE(entry->dir_files, s) eina_stringshare_del(s); free(entry); } @@ -545,4 +541,3 @@ ephoto_entries_free(Ephoto *ephoto) Ephoto_Entry *entry; EINA_LIST_FREE(ephoto->entries, entry) ephoto_entry_free(entry); } - diff --git a/src/bin/ephoto_single_browser.c b/src/bin/ephoto_single_browser.c index 8e64c9b..d6af5b3 100644 --- a/src/bin/ephoto_single_browser.c +++ b/src/bin/ephoto_single_browser.c @@ -8,53 +8,52 @@ * 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 ROTATION 0 #define ZOOM_STEP 0.2 -typedef struct _Ephoto_Single_Browser Ephoto_Single_Browser; +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 *main; + Evas_Object *bar; + Evas_Object *label; Evas_Object *viewer; const char *pending_path; Ephoto_Entry *entry; Ephoto_Orient orient; Eina_List *handlers; - Eina_List *entries; - Eina_List *current_index; }; struct _Ephoto_Viewer { - Evas_Object *scroller; - Evas_Object *box; - Evas_Object *image; 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; + if (len < sizeof(".jpg")) return EINA_FALSE; ext = path_stringshared + len - (sizeof(".jpg") - 1); - if (strcasecmp(ext, ".jpg") == 0) - return EINA_TRUE; + if (strcasecmp(ext, ".jpg") == 0) return EINA_TRUE; - if (len < sizeof(".jpeg")) - return EINA_FALSE; + if (len < sizeof(".jpeg")) return EINA_FALSE; ext = path_stringshared + len - (sizeof(".jpeg") - 1); - if (strcasecmp(ext, ".jpeg") == 0) - return EINA_TRUE; + if (strcasecmp(ext, ".jpeg") == 0) return EINA_TRUE; return EINA_FALSE; } @@ -69,7 +68,6 @@ static void _viewer_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { Ephoto_Viewer *v = data; - free(v); } @@ -86,8 +84,7 @@ _viewer_add(Evas_Object *parent, const char *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; + 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); @@ -97,25 +94,14 @@ _viewer_add(Evas_Object *parent, const char *path) Evas_Coord w, h; obj = v->scroller = elm_scroller_add(parent); EINA_SAFETY_ON_NULL_GOTO(obj, error); - - v->box = elm_box_add(obj); - evas_object_size_hint_weight_set(v->box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_size_hint_align_set(v->box, EVAS_HINT_FILL, EVAS_HINT_FILL); - evas_object_show(v->box); - 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_weight_set(v->image, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); 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_box_pack_end(v->box, v->image); - elm_scroller_content_set(obj, v->box); } 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); @@ -135,20 +121,15 @@ 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); + 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; + h *= zoom; evas_object_size_hint_min_set(v->image, w, h); evas_object_size_hint_max_set(v->image, w, h); - elm_box_unpack(v->box, v->image); - elm_scroller_content_unset(v->scroller); - elm_box_pack_end(v->box, v->image); - elm_scroller_content_set(v->scroller, v->box); } } @@ -218,10 +199,10 @@ _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); @@ -232,18 +213,288 @@ _viewer_zoom_fit(Evas_Object *obj) _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) +{ + const Eina_List *l; + Ephoto_Entry *entry; + EINA_SAFETY_ON_NULL_RETURN_VAL(sb->ephoto, NULL); + + EINA_LIST_FOREACH(sb->ephoto->entries, l, entry) + if (!entry->is_dir) return entry; + return NULL; +} + +static Ephoto_Entry * +_last_entry_find(Ephoto_Single_Browser *sb) +{ + const Eina_List *l; + Ephoto_Entry *entry; + EINA_SAFETY_ON_NULL_RETURN_VAL(sb->ephoto, NULL); + + EINA_LIST_REVERSE_FOREACH(sb->ephoto->entries, l, entry) + if (!entry->is_dir) return entry; + return NULL; +} + +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->main, sb->entry->path); + elm_box_pack_end(sb->main, sb->viewer); + evas_object_show(sb->viewer); + evas_object_event_callback_add + (sb->viewer, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel, sb); + elm_label_label_set(sb->label, bname); + ephoto_title_set(sb->ephoto, bname); + sb->orient = ephoto_file_orient_get(sb->entry->path); + _orient_apply(sb); + } + + elm_object_focus(sb->main); +} + 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); + _viewer_zoom_set(sb->viewer, zoom); } static void _zoom_fit(Ephoto_Single_Browser *sb) { - if (sb->viewer) - _viewer_zoom_fit(sb->viewer); + if (sb->viewer) _viewer_zoom_fit(sb->viewer); } static void @@ -260,6 +511,34 @@ _zoom_out(Ephoto_Single_Browser *sb) _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; + _zoom_in(sb); +} + +static void +_zoom_out_cb(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + _zoom_out(sb); +} + +static void +_zoom_1_cb(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + _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; + _zoom_fit(sb); +} + static int _entry_cmp(const void *pa, const void *pb) { @@ -272,20 +551,6 @@ _entry_cmp(const void *pa, const void *pb) return strcoll(a->path, path); } -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 _next_entry(Ephoto_Single_Browser *sb) { @@ -294,90 +559,135 @@ _next_entry(Ephoto_Single_Browser *sb) EINA_SAFETY_ON_NULL_RETURN(sb->entry); node = eina_list_search_sorted_list(sb->ephoto->entries, _entry_cmp, sb->entry->path); - if (!node) - return; - if ((node = node->next)) + if (!node) return; + while ((node = node->next)) { entry = node->data; + if (!entry->is_dir) + break; } if (!entry) entry = _first_entry_find(sb); if (entry) - ephoto_single_browser_entry_set(sb->layout, entry); + { + DBG("next is '%s'", entry->path); + ephoto_single_browser_entry_set(sb->main, entry); + } } static void _prev_entry(Ephoto_Single_Browser *sb) { - Ephoto_Entry *entry = NULL; 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; - if ((node = node->prev)) + if (!node) return; + while ((node = node->prev)) { entry = node->data; + if (!entry->is_dir) + break; } if (!entry) entry = _last_entry_find(sb); if (entry) - ephoto_single_browser_entry_set(sb->layout, entry); + { + DBG("prev is '%s'", entry->path); + ephoto_single_browser_entry_set(sb->main, entry); + } } static void _first_entry(Ephoto_Single_Browser *sb) { Ephoto_Entry *entry = _first_entry_find(sb); - - if (!entry) - return; - ephoto_single_browser_entry_set(sb->layout, entry); + if (!entry) return; + DBG("first is '%s'", entry->path); + ephoto_single_browser_entry_set(sb->main, entry); } static void _last_entry(Ephoto_Single_Browser *sb) { Ephoto_Entry *entry = _last_entry_find(sb); - - if (!entry) - return; - ephoto_single_browser_entry_set(sb->layout, entry); + if (!entry) return; + DBG("last is '%s'", entry->path); + ephoto_single_browser_entry_set(sb->main, entry); } static void -_viewer_scrolled(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +_go_first(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) { Ephoto_Single_Browser *sb = data; - Ephoto_Viewer *v = evas_object_data_get(sb->viewer, "viewer"); - int sx, sw, cx; - if (!v->fit) - return; - evas_object_geometry_get(sb->viewer, &sx, 0, &sw, 0); - if (v->photocam) - { - Evas_Object *i = elm_photocam_internal_image_get(v->photocam); - evas_object_geometry_get(i, &cx, 0, 0, 0); - } - else - evas_object_geometry_get(v->image, &cx, 0, 0, 0); - if (cx < (sx-(sw/2))) - _next_entry(sb); - else if (cx > (sw/2)) - _prev_entry(sb); + _first_entry(sb); } static void -_mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info) +_go_prev(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) { Ephoto_Single_Browser *sb = data; - Ephoto_Viewer *v = evas_object_data_get(sb->viewer, "viewer"); - Evas_Event_Mouse_Wheel *ev = event_info; - if (!evas_key_modifier_is_set(ev->modifiers, "Control")) return; + _prev_entry(sb); +} - if (ev->z > 0) _zoom_set(sb, v->zoom + ZOOM_STEP); - else _zoom_set(sb, v->zoom - ZOOM_STEP); +static void +_go_next(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + _next_entry(sb); +} + +static void +_go_last(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + _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; + _rotate_counterclock(sb); +} + +static void +_go_rotate_clock(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + _rotate_clock(sb); +} + +static void +_go_flip_horiz(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + _flip_horiz(sb); +} + +static void +_go_flip_vert(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + _flip_vert(sb); +} +#endif + +static void +_slideshow(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + if (sb->entry) + evas_object_smart_callback_call(sb->main, "slideshow", sb->entry); +} + +static void +_back(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + Ephoto_Single_Browser *sb = data; + evas_object_smart_callback_call(sb->main, "back", sb->entry); } static void @@ -389,6 +699,7 @@ _key_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event 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"))) @@ -403,7 +714,10 @@ _key_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event return; } - if (!strcmp(k, "Left") || !strcmp(k, "BackSpace")) + + if (!strcmp(k, "Escape")) + evas_object_smart_callback_call(sb->main, "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); @@ -411,31 +725,23 @@ _key_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event _first_entry(sb); else if (!strcmp(k, "End")) _last_entry(sb); -} - -static void -_ephoto_single_browser_recalc(Ephoto_Single_Browser *sb) -{ - if (sb->viewer) +#if ROTATION + else if (!strcmp(k, "bracketleft")) { - evas_object_del(sb->viewer); - sb->viewer = NULL; + if (!shift) _rotate_counterclock(sb); + else _flip_horiz(sb); } - - if (sb->entry) + else if (!strcmp(k, "bracketright")) { - const char *bname = ecore_file_file_get(sb->entry->path); - sb->viewer = _viewer_add(sb->layout, sb->entry->path); - elm_layout_content_set(sb->layout, "ephoto.swallow.content", sb->viewer); - evas_object_event_callback_add - (sb->viewer, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel, sb); - evas_object_smart_callback_add - (sb->viewer, "scroll", _viewer_scrolled, sb); - evas_object_show(sb->viewer); - ephoto_title_set(sb->ephoto, bname); + if (!shift) _rotate_clock(sb); + else _flip_vert(sb); + } +#endif + else if (!strcmp(k, "F5")) + { + if (sb->entry) + evas_object_smart_callback_call(sb->main, "slideshow", sb->entry); } - - elm_object_focus(sb->layout); } static void @@ -446,7 +752,7 @@ _entry_free(void *data, const Ephoto_Entry *entry __UNUSED__) } static void -_layout_del(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +_main_del(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) { Ephoto_Single_Browser *sb = data; Ecore_Event_Handler *handler; @@ -476,6 +782,8 @@ _ephoto_single_entry_create(void *data, int type __UNUSED__, void *event __UNUSE 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); @@ -487,26 +795,161 @@ _ephoto_single_entry_create(void *data, int type __UNUSED__, void *event __UNUSE Evas_Object * ephoto_single_browser_add(Ephoto *ephoto, Evas_Object *parent) { + Evas_Object *box = elm_box_add(parent); + Evas_Object *but, *ic, *sep; Ephoto_Single_Browser *sb; + EINA_SAFETY_ON_NULL_RETURN_VAL(box, NULL); + sb = calloc(1, sizeof(Ephoto_Single_Browser)); EINA_SAFETY_ON_NULL_GOTO(sb, error); sb->ephoto = ephoto; + sb->main = box; + elm_box_horizontal_set(sb->main, EINA_FALSE); + elm_box_homogeneous_set(sb->main, EINA_FALSE); + evas_object_event_callback_add(sb->main, EVAS_CALLBACK_DEL, _main_del, sb); + evas_object_event_callback_add + (sb->main, EVAS_CALLBACK_KEY_DOWN, _key_down, sb); + evas_object_data_set(sb->main, "single_browser", sb); - sb->layout = elm_layout_add(parent); - if (!elm_layout_file_set(sb->layout, THEME_FILE, "ephoto/layout/single/browser")) - { - ERR("Could not load style 'ephoto/layout/single/browser' from theme"); - goto error; - } - evas_object_size_hint_weight_set - (sb->layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_size_hint_fill_set - (sb->layout, EVAS_HINT_FILL, EVAS_HINT_FILL); - evas_object_event_callback_add(sb->layout, EVAS_CALLBACK_KEY_DOWN, _key_down, sb); - evas_object_event_callback_add(sb->layout, EVAS_CALLBACK_DEL, _layout_del, sb); - evas_object_data_set(sb->layout, "single_browser", sb); - evas_object_show(sb->layout); + sb->bar = elm_box_add(sb->main); + elm_box_horizontal_set(sb->bar, EINA_TRUE); + elm_box_homogeneous_set(sb->bar, EINA_FALSE); + evas_object_size_hint_weight_set(sb->bar, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(sb->bar, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(sb->bar); + elm_box_pack_end(sb->main, sb->bar); + + but = elm_button_add(sb->bar); + + ic = elm_icon_add(but); + elm_icon_file_set(ic, PACKAGE_DATA_DIR "/images/back_grid.png", NULL); + + elm_button_icon_set(but, ic); + evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(but, "clicked", _back, sb); + elm_box_pack_end(sb->bar, but); + evas_object_show(but); + + sep = elm_separator_add(sb->bar); + elm_box_pack_end(sb->bar, sep); + evas_object_show(sep); + + but = elm_button_add(sb->bar); + + ic = elm_icon_add(but); + elm_icon_file_set(ic, PACKAGE_DATA_DIR "/images/zoom-in.png", NULL); + + elm_button_icon_set(but, ic); + evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(but, "clicked", _zoom_in_cb, sb); + elm_box_pack_end(sb->bar, but); + evas_object_show(but); + + but = elm_button_add(sb->bar); + + ic = elm_icon_add(but); + elm_icon_file_set(ic, PACKAGE_DATA_DIR "/images/zoom-out.png", NULL); + + elm_button_icon_set(but, ic); + evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(but, "clicked", _zoom_out_cb, sb); + elm_box_pack_end(sb->bar, but); + evas_object_show(but); + + but = elm_button_add(sb->bar); + + ic = elm_icon_add(but); + elm_icon_file_set(ic, PACKAGE_DATA_DIR "/images/zoom-fit.png", NULL); + + elm_button_icon_set(but, ic); + evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(but, "clicked", _zoom_fit_cb, sb); + elm_box_pack_end(sb->bar, but); + evas_object_show(but); + + but = elm_button_add(sb->bar); + + ic = elm_icon_add(but); + elm_icon_file_set(ic, PACKAGE_DATA_DIR "/images/zoom-original.png", NULL); + + elm_button_icon_set(but, ic); + evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(but, "clicked", _zoom_1_cb, sb); + elm_box_pack_end(sb->bar, but); + evas_object_show(but); + + sep = elm_separator_add(sb->bar); + elm_box_pack_end(sb->bar, sep); + evas_object_show(sep); + + sb->label = elm_label_add(sb->bar); + evas_object_size_hint_align_set(sb->label, 0.5, 0.5); + elm_box_pack_end(sb->bar, sb->label); + evas_object_show(sb->label); + + sep = elm_separator_add(sb->bar); + elm_box_pack_end(sb->bar, sep); + evas_object_show(sep); + + but = elm_button_add(sb->bar); + + ic = elm_icon_add(but); + elm_icon_file_set(ic, PACKAGE_DATA_DIR "/images/first.png", NULL); + + elm_button_icon_set(but, ic); + evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(but, "clicked", _go_first, sb); + elm_box_pack_end(sb->bar, but); + evas_object_show(but); + + but = elm_button_add(sb->bar); + + ic = elm_icon_add(but); + elm_icon_file_set(ic, PACKAGE_DATA_DIR "/images/back.png", NULL); + + elm_button_icon_set(but, ic); + evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(but, "clicked", _go_prev, sb); + elm_box_pack_end(sb->bar, but); + evas_object_show(but); + + but = elm_button_add(sb->bar); + + ic = elm_icon_add(but); + elm_icon_file_set(ic, PACKAGE_DATA_DIR "/images/forward.png", NULL); + + elm_button_icon_set(but, ic); + evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(but, "clicked", _go_next, sb); + elm_box_pack_end(sb->bar, but); + evas_object_show(but); + + but = elm_button_add(sb->bar); + + ic = elm_icon_add(but); + elm_icon_file_set(ic, PACKAGE_DATA_DIR "/images/last.png", NULL); + + elm_button_icon_set(but, ic); + evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(but, "clicked", _go_last, sb); + elm_box_pack_end(sb->bar, but); + evas_object_show(but); + + sep = elm_separator_add(sb->bar); + elm_box_pack_end(sb->bar, sep); + evas_object_show(sep); + + but = elm_button_add(sb->bar); + + ic = elm_icon_add(but); + elm_icon_file_set(ic, PACKAGE_DATA_DIR "/images/slideshow.png", NULL); + + elm_button_icon_set(but, ic); + evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(but, "clicked", _slideshow, sb); + elm_box_pack_end(sb->bar, but); + evas_object_show(but); sb->handlers = eina_list_append (sb->handlers, ecore_event_handler_add @@ -514,12 +957,12 @@ ephoto_single_browser_add(Ephoto *ephoto, Evas_Object *parent) sb->handlers = eina_list_append (sb->handlers, ecore_event_handler_add - (EPHOTO_EVENT_ENTRY_CREATE_THUMB, _ephoto_single_entry_create, sb)); + (EPHOTO_EVENT_ENTRY_CREATE, _ephoto_single_entry_create, sb)); - return sb->layout; + return sb->main; error: - evas_object_del(sb->layout); + evas_object_del(sb->main); return NULL; } @@ -527,26 +970,19 @@ 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); - if (sb->entry) - { - ephoto_entry_free_listener_del(sb->entry, _entry_free, sb); - if (entry && entry->path == sb->entry->path) - same_file = EINA_TRUE; - } + DBG("entry %p, was %p", entry, sb->entry); + if (sb->entry) + ephoto_entry_free_listener_del(sb->entry, _entry_free, sb); + sb->entry = entry; if (entry) ephoto_entry_free_listener_add(entry, _entry_free, sb); - - if (sb->entry || !same_file) - { - _ephoto_single_browser_recalc(sb); - _zoom_fit(sb); - } + _ephoto_single_browser_recalc(sb); + _zoom_fit(sb); } void @@ -558,4 +994,3 @@ ephoto_single_browser_path_pending_set(Evas_Object *obj, const char *path) 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 new file mode 100644 index 0000000..5bfbed6 --- /dev/null +++ b/src/bin/ephoto_slideshow.c @@ -0,0 +1,193 @@ +#include "ephoto.h" + +typedef struct _Ephoto_Slideshow Ephoto_Slideshow; + +struct _Ephoto_Slideshow +{ + Ephoto *ephoto; + Evas_Object *slideshow; + Ephoto_Entry *entry; +}; + +static void +_key_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info) +{ + Ephoto_Slideshow *ss = data; + Evas_Event_Key_Down *ev = event_info; + const char *k = ev->keyname; + + if (!strcmp(k, "Escape")) + { + Evas_Object *win = ss->ephoto->win; + Elm_Slideshow_Item *item; + Ephoto_Entry *entry; + + 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 +_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 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 const Elm_Slideshow_Item_Class _item_cls = {{_slideshow_item_get, NULL}}; + +void +ephoto_slideshow_entry_set(Evas_Object *obj, Ephoto_Entry *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; + if (itr->is_dir) continue; + 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 6242e46..b55cd32 100644 --- a/src/bin/ephoto_thumb_browser.c +++ b/src/bin/ephoto_thumb_browser.c @@ -6,21 +6,31 @@ #define TODO_ITEM_MIN_BATCH 16 +#define PARENT_DIR "Up" + typedef struct _Ephoto_Thumb_Browser Ephoto_Thumb_Browser; struct _Ephoto_Thumb_Browser { Ephoto *ephoto; - Ephoto_Entry *entry; + Evas_Object *main; + Evas_Object *bar; + Evas_Object *fsel; Evas_Object *grid; Eio_File *ls; Eina_List *todo_items; Eina_List *grid_items; Eina_List *handlers; + struct { + Elm_Toolbar_Item *zoom_in; + Elm_Toolbar_Item *zoom_out; + Elm_Toolbar_Item *view_single; + Elm_Toolbar_Item *slideshow; + } action; struct { Ecore_Animator *todo_items; } animator; - Eina_Bool layout_deleted : 1; + Eina_Bool main_deleted : 1; }; static void @@ -37,6 +47,16 @@ _grid_items_free(Ephoto_Thumb_Browser *tb) tb->grid_items = NULL; } +static Ephoto_Entry * +_first_file_entry_find(Ephoto_Thumb_Browser *tb) +{ + const Eina_List *l; + Ephoto_Entry *entry; + EINA_LIST_FOREACH(tb->ephoto->entries, l, entry) + if (!entry->is_dir) return entry; + return NULL; +} + static char * _ephoto_thumb_item_label_get(void *data, Evas_Object *obj __UNUSED__, const char *part __UNUSED__) { @@ -44,6 +64,54 @@ _ephoto_thumb_item_label_get(void *data, Evas_Object *obj __UNUSED__, const char return strdup(e->label); } +static Evas_Object * +_ephoto_thumb_dir_icon_get(void *data, Evas_Object *obj, const char *part) +{ + Ephoto_Entry *e = data; + const char *f; + int n; + + if (strncmp(part, "elm.swallow.icon.", sizeof("elm.swallow.icon.") - 1) != 0) + return NULL; + + n = atoi(part + sizeof("elm.swallow.icon.") - 1); + if (n < 1) + return NULL; + n--; + + f = eina_list_nth(e->dir_files, n); + if (f) + { + Evas_Object *o; + o = ephoto_thumb_add(e->ephoto, obj, f); + //elm_object_style_set(o, "default"); + return o; + } + + if (e->dir_files_checked) + return NULL; + + return ephoto_directory_thumb_add(obj, e); +} + +static Eina_Bool +_ephoto_thumb_dir_state_get(void *data, Evas_Object *obj __UNUSED__, const char *part) +{ + Ephoto_Entry *e = data; + int n; + + if (strcmp(part, "have_files") == 0) + return !!e->dir_files; + + if (strncmp(part, "have_file.", sizeof("have_file.") - 1) != 0) + return EINA_FALSE; + + n = atoi(part + sizeof("have_file.") - 1); + if (n < 1) + return EINA_FALSE; + return n <= (int)eina_list_count(e->dir_files); +} + static Evas_Object * _ephoto_thumb_file_icon_get(void *data, Evas_Object *obj, const char *part __UNUSED__) { @@ -62,6 +130,26 @@ _ephoto_thumb_item_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__) */ } +static const Elm_Gengrid_Item_Class _ephoto_thumb_up_class = { + "ephoto-up", + { + _ephoto_thumb_item_label_get, + NULL, + NULL, + _ephoto_thumb_item_del + } +}; + +static const Elm_Gengrid_Item_Class _ephoto_thumb_dir_class = { + "ephoto-album-preview", + { + _ephoto_thumb_item_label_get, + _ephoto_thumb_dir_icon_get, + _ephoto_thumb_dir_state_get, + _ephoto_thumb_item_del + } +}; + static const Elm_Gengrid_Item_Class _ephoto_thumb_file_class = { "thumb", { @@ -75,56 +163,59 @@ static const Elm_Gengrid_Item_Class _ephoto_thumb_file_class = { static int _entry_cmp(const void *pa, const void *pb) { - const Ephoto_Entry *a = pa, *b = pb; - int ret, s; - - s = strcmp(a->basename, b->basename); - if (s > 0) - ret = 1; - else if (s < 0) - ret = -1; + const Elm_Gengrid_Item *ia = pa; + const Ephoto_Entry *a, *b = pb; + + a = elm_gengrid_item_data_get(ia); + + if (a->is_dir == b->is_dir) + return strcoll(a->basename, b->basename); + else if (a->is_dir) + return -1; else - ret = 0; - return ret; + return 1; } static void _entry_item_add(Ephoto_Thumb_Browser *tb, Ephoto_Entry *e) { const Elm_Gengrid_Item_Class *ic; - - ic = &_ephoto_thumb_file_class; + int near_cmp; + Elm_Gengrid_Item *near_item = NULL; + Eina_List *near_node = NULL; + + near_node = eina_list_search_sorted_near_list + (tb->grid_items, _entry_cmp, e, &near_cmp); - if (!tb->grid_items) + if (near_node) + near_item = near_node->data; + + if (e->is_dir) ic = &_ephoto_thumb_dir_class; + else ic = &_ephoto_thumb_file_class; + + if (!near_item) { e->item = elm_gengrid_item_append(tb->grid, ic, e, NULL, NULL); - tb->grid_items = eina_list_append(tb->grid_items, e); + tb->grid_items = eina_list_append(tb->grid_items, e->item); } else { - int near_cmp; - Ephoto_Entry *near_entry; - Elm_Gengrid_Item *near_item; - Eina_List *near_node = eina_list_search_sorted_near_list - (tb->grid_items, _entry_cmp, e, &near_cmp); - - near_entry = near_node->data; - near_item = near_entry->item; if (near_cmp < 0) { e->item = elm_gengrid_item_insert_after - (tb->grid, ic, e, near_item, NULL, NULL); - tb->grid_items = eina_list_append_relative_list - (tb->grid_items, e, near_node); + (tb->grid, ic, e, near_item, NULL, NULL); + tb->grid_items = eina_list_append_relative + (tb->grid_items, e->item, near_item); } else { e->item = elm_gengrid_item_insert_before - (tb->grid, ic, e, near_item, NULL, NULL); - tb->grid_items = eina_list_prepend_relative_list - (tb->grid_items, e, near_node); + (tb->grid, ic, e, near_item, NULL, NULL); + tb->grid_items = eina_list_prepend_relative + (tb->grid_items, e->item, near_item); } } + if (e->item) elm_gengrid_item_data_set(e->item, e); else @@ -135,6 +226,27 @@ _entry_item_add(Ephoto_Thumb_Browser *tb, Ephoto_Entry *e) } } +static void +_up_item_add_if_required(Ephoto_Thumb_Browser *tb) +{ + Ephoto_Entry *entry; + char *parent_dir; + + if ((strcmp(tb->ephoto->config->directory, "/") == 0)) + return; + + parent_dir = ecore_file_dir_get(tb->ephoto->config->directory); + if (!parent_dir) return; + + entry = ephoto_entry_new(tb->ephoto, parent_dir, PARENT_DIR); + free(parent_dir); + EINA_SAFETY_ON_NULL_RETURN(entry); + entry->is_up = EINA_TRUE; + entry->is_dir = EINA_TRUE; + entry->item = elm_gengrid_item_append + (tb->grid, &_ephoto_thumb_up_class, entry, NULL, NULL); +} + static Eina_Bool _todo_items_process(void *data) { @@ -144,6 +256,8 @@ _todo_items_process(void *data) if ((tb->ls) && (eina_list_count(tb->todo_items) < TODO_ITEM_MIN_BATCH)) return EINA_TRUE; + _up_item_add_if_required(tb); + tb->animator.todo_items = NULL; EINA_LIST_FREE(tb->todo_items, entry) @@ -161,7 +275,28 @@ _ephoto_thumb_selected(void *data, Evas_Object *o __UNUSED__, void *event_info) elm_gengrid_item_selected_set(it, EINA_FALSE); - ephoto_promote_single_browser(tb->ephoto, e); + if (e->is_dir) + ephoto_directory_set(tb->ephoto, e->path); + else + evas_object_smart_callback_call(tb->main, "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 @@ -175,7 +310,98 @@ _zoom_set(Ephoto_Thumb_Browser *tb, int zoom) } static void -_grid_del(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +_zoom_in(void *data, Evas_Object *o, void *event_info __UNUSED__) +{ + Ephoto_Thumb_Browser *tb = data; + Evas_Object *min = evas_object_data_get(o, "min"); + int zoom = tb->ephoto->config->thumb_size + ZOOM_STEP; + _zoom_set(tb, zoom); + if (zoom >= ZOOM_MAX) elm_object_disabled_set(o, EINA_TRUE); + if (zoom > ZOOM_MIN) elm_object_disabled_set(min, EINA_FALSE); +} + +static void +_zoom_out(void *data, Evas_Object *o, void *event_info __UNUSED__) +{ + Ephoto_Thumb_Browser *tb = data; + Evas_Object *max = evas_object_data_get(o, "max"); + int zoom = tb->ephoto->config->thumb_size - ZOOM_STEP; + _zoom_set(tb, zoom); + if (zoom <= ZOOM_MIN) elm_object_disabled_set(o, EINA_TRUE); + if (zoom < ZOOM_MAX) elm_object_disabled_set(max, EINA_FALSE); +} + +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; + + if (it) entry = elm_gengrid_item_data_get(it); + else entry = _first_file_entry_find(tb); + + if (!entry) return; + if (entry->is_dir) + ephoto_directory_set(tb->ephoto, entry->path); + else + evas_object_smart_callback_call(tb->main, "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; + + 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->main, "slideshow", 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->main, "slideshow", entry); + } +} + + +static void +_main_del(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) { Ephoto_Thumb_Browser *tb = data; Ecore_Event_Handler *handler; @@ -192,7 +418,7 @@ _grid_del(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event } if (tb->ls) { - tb->layout_deleted = EINA_TRUE; + tb->main_deleted = EINA_TRUE; eio_file_cancel(tb->ls); return; } @@ -204,9 +430,12 @@ _ephoto_thumb_populate_start(void *data, int type __UNUSED__, void *event __UNUS { Ephoto_Thumb_Browser *tb = data; + evas_object_smart_callback_call(tb->main, "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); return ECORE_CALLBACK_PASS_ON; } @@ -217,12 +446,14 @@ _ephoto_thumb_populate_end(void *data, int type __UNUSED__, void *event __UNUSED Ephoto_Thumb_Browser *tb = data; tb->ls = NULL; - if (tb->layout_deleted) + if (tb->main_deleted) { free(tb); return ECORE_CALLBACK_PASS_ON; } + if (!tb->animator.todo_items) _up_item_add_if_required(tb); + return ECORE_CALLBACK_PASS_ON; } @@ -251,26 +482,116 @@ _ephoto_thumb_entry_create(void *data, int type __UNUSED__, void *event) Evas_Object * ephoto_thumb_browser_add(Ephoto *ephoto, Evas_Object *parent) { + Evas_Object *box = elm_box_add(parent); + Evas_Object *ic, *but, *min, *max; Ephoto_Thumb_Browser *tb; + EINA_SAFETY_ON_NULL_RETURN_VAL(box, NULL); + tb = calloc(1, sizeof(Ephoto_Thumb_Browser)); EINA_SAFETY_ON_NULL_GOTO(tb, error); - tb->ephoto = ephoto; - tb->grid = elm_gengrid_add(parent); + elm_theme_extension_add(NULL, PACKAGE_DATA_DIR "/themes/default/ephoto.edj"); + + tb->ephoto = ephoto; + tb->main = box; + elm_box_horizontal_set(tb->main, EINA_FALSE); + elm_box_homogeneous_set(tb->main, EINA_FALSE); + evas_object_event_callback_add(tb->main, EVAS_CALLBACK_DEL, _main_del, tb); + evas_object_event_callback_add + (tb->main, EVAS_CALLBACK_KEY_DOWN, _key_down, tb); + evas_object_data_set(tb->main, "thumb_browser", tb); + + tb->bar = elm_box_add(tb->main); + elm_box_horizontal_set(tb->bar, EINA_TRUE); + elm_box_homogeneous_set(tb->bar, EINA_FALSE); + evas_object_size_hint_weight_set(tb->bar, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(tb->bar, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(tb->bar); + elm_box_pack_end(tb->main, tb->bar); + + but = elm_button_add(tb->bar); + + ic = elm_icon_add(but); + elm_icon_file_set(ic, PACKAGE_DATA_DIR "/images/single.png", NULL); + + elm_button_icon_set(but, ic); + evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(but, "clicked", _view_single, tb); + elm_box_pack_end(tb->bar, but); + evas_object_show(but); + + but = elm_button_add(tb->bar); + + ic = elm_icon_add(but); + elm_icon_file_set(ic, PACKAGE_DATA_DIR "/images/slideshow.png", NULL); + + elm_button_icon_set(but, ic); + evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(but, "clicked", _slideshow, tb); + elm_box_pack_end(tb->bar, but); + evas_object_show(but); + + tb->fsel = elm_fileselector_entry_add(tb->bar); + 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_box_pack_end(tb->bar, tb->fsel); + + but = elm_button_add(tb->bar); + + ic = elm_icon_add(but); + elm_icon_file_set(ic, PACKAGE_DATA_DIR "/images/zoom-in.png", NULL); + + elm_button_icon_set(but, ic); + evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(but, "clicked", _zoom_in, tb); + elm_box_pack_end(tb->bar, but); + evas_object_show(but); + max = but; + + but = elm_button_add(tb->bar); + + ic = elm_icon_add(but); + elm_icon_file_set(ic, PACKAGE_DATA_DIR "/images/zoom-out.png", NULL); + + elm_button_icon_set(but, ic); + evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(but, "clicked", _zoom_out, tb); + elm_box_pack_end(tb->bar, but); + evas_object_show(but); + min = but; + + evas_object_data_set(max, "min", min); + evas_object_data_set(min, "max", max); + + tb->grid = elm_gengrid_add(tb->main); EINA_SAFETY_ON_NULL_GOTO(tb->grid, error); + evas_object_size_hint_weight_set + (tb->grid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(tb->grid, EVAS_HINT_FILL, EVAS_HINT_FILL); + 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_event_callback_add(tb->grid, EVAS_CALLBACK_DEL, _grid_del, tb); - evas_object_data_set(tb->grid, "thumb_browser", tb); + evas_object_show(tb->grid); + elm_box_pack_end(tb->main, tb->grid); tb->handlers = eina_list_append (tb->handlers, ecore_event_handler_add @@ -286,18 +607,11 @@ ephoto_thumb_browser_add(Ephoto *ephoto, Evas_Object *parent) tb->handlers = eina_list_append (tb->handlers, ecore_event_handler_add - (EPHOTO_EVENT_ENTRY_CREATE_THUMB, _ephoto_thumb_entry_create, tb)); + (EPHOTO_EVENT_ENTRY_CREATE, _ephoto_thumb_entry_create, tb)); - return tb->grid; + return tb->main; error: - evas_object_del(tb->grid); + evas_object_del(tb->main); return NULL; } - -void -ephoto_thumb_browser_entry_set(Evas_Object *obj, Ephoto_Entry *entry) -{ - Ephoto_Thumb_Browser *tb = evas_object_data_get(obj, "thumb_browser"); - tb->entry = entry; -}