From 35104b170a65ebcef9bf606d313a832523a31562 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Wed, 17 Dec 2014 13:59:53 +0300 Subject: [PATCH] FileDialog - continue development; drive list --- examples/example1/src/main.d | 5 + res/mdpi/computer.png | Bin 0 -> 1609 bytes res/mdpi/drive-harddisk.png | Bin 0 -> 1450 bytes res/mdpi/drive-optical.png | Bin 0 -> 1506 bytes res/mdpi/drive-removable-media.png | Bin 0 -> 1037 bytes res/mdpi/folder-blue.png | Bin 0 -> 1539 bytes res/mdpi/folder-bookmark.png | Bin 0 -> 1704 bytes res/mdpi/folder-network.png | Bin 0 -> 1731 bytes res/mdpi/media-flash-sd-mmc.png | Bin 0 -> 1709 bytes res/mdpi/user-home.png | Bin 0 -> 1698 bytes src/dlangui/core/files.d | 253 +++++++++++++++++++++++++++++ src/dlangui/dialogs/filedlg.d | 56 +++++-- src/dlangui/widgets/controls.d | 53 ++++-- src/dlangui/widgets/lists.d | 2 +- 14 files changed, 342 insertions(+), 27 deletions(-) create mode 100644 res/mdpi/computer.png create mode 100644 res/mdpi/drive-harddisk.png create mode 100644 res/mdpi/drive-optical.png create mode 100644 res/mdpi/drive-removable-media.png create mode 100644 res/mdpi/folder-blue.png create mode 100644 res/mdpi/folder-bookmark.png create mode 100644 res/mdpi/folder-network.png create mode 100644 res/mdpi/media-flash-sd-mmc.png create mode 100644 res/mdpi/user-home.png create mode 100644 src/dlangui/core/files.d diff --git a/examples/example1/src/main.d b/examples/example1/src/main.d index 8c26a4ea..b4717d58 100644 --- a/examples/example1/src/main.d +++ b/examples/example1/src/main.d @@ -717,5 +717,10 @@ extern (C) int UIAppMain(string[] args) { window.show(); //window.windowCaption = "New Window Caption"; // run message loop + + Log.i("HOME path: ", homePath); + Log.i("APPDATA path: ", appDataPath(".dlangui")); + Log.i("Root paths: ", getRootPaths); + return Platform.instance.enterMessageLoop(); } diff --git a/res/mdpi/computer.png b/res/mdpi/computer.png new file mode 100644 index 0000000000000000000000000000000000000000..a5ee195612c8131e0217c89b8c9f77616cb7d6f0 GIT binary patch literal 1609 zcmV-P2DbT$P)Px#32;bRa{vGa>;M1;>;WEiI5hwO00(qQO+^RT2py{D4^00qfOL_t(|+U-|OY*bYg{^rdaI_;EBTcFg^&_V+(p_q{LM~F6&vM}yk zxF^vBVFBnysA7x>3p5Q$ffXhttgM7BaZ_W!D3C%WY#=FVYXxj)+UYn<=gqu7&$+jE zuGisbVO;6yoSggaySe8(-#PcZTm0uGg6GKHyLX4Hs;Z8}<8j-vEJPv^L!ULr5{BV3 zH3$OZ*>N1NSS*gb2!Pw%+-x5@bO>wKtPu{Q(I{J`6+o1jPNnsIpRG{O^Kka;S#`RBFBJIIcJf+fZNplU+_j-Jy!R&*~xkykUk|{p-lrw zDM!%Q^%_o`96|_44Oicn!IH|6o?BJ$y9nVVHf%r@<+-M& z1|J+eh^tqxVrptiFC?!ePe)qGf;kt8KPi8>z;EQ-rx}?r7{S?-latuk)P(BlYV`K@ zqADIoP*Fr7if*6*7}P5jAsc{Fg%Bx6u9kJfduafyc4t?Y0Pv6^UUof{_Pvdnydz#} z1p$Ccfu`TcH-nZ>9@)qF0C_iL$5LeRaxi8JJkN#idGJVi;?YV02+c)g;JASiwUK{4 zhT{WIh;lcSl#3rLFERi~wOp5+`@R5>jM>=o^Y>`2vh@OS=A$UN3_>#Dl-QCA8!|YW zBf81)^pZ#8fPxB1*~+meo*9(rCprbL>+(Q=fXqFEQ42(E*wGkoYUEsxWm=Y~#B(Kf zfO5ak<4`fdCyJYr37}Leq3BTFWfBdFve_)0xI+L`otgp|Q8EyPfC|6%43O$P9RajGP{&BZKCO$a$>iE%D63m<-&xeH-i6 zH6m(75o!QNo_Lg_LUTMG>CKI=pB3RBK+Y`X+zK@iRHi_F3wG=f-+=Agw!sw5L}_Uj zGZW)#N=K*w=v+$>mS(}yH6YgJ9^FS^=~}Z%_^ccGSGiS*J598mER4V0>8DRjj^M!=m zbx})A!Y&jLi^VW9GJ>7EcA=rM5&b}k|A9n8S#-~F=4FHyTZ_4ejEiElRotmiYy2@!q|KOA=Fw6q6?BBR?WA;V=nAlBC zO|Q^t*pgk&w#2Ke?L=*2-gmuO%IRZqW0n%{@9*z9aNxlEt*xzZZQ8VHJ%No9-HHuW zh+Gf;%*;%BZf@?oOP4Nvee>qc2>?z70AtLm$Dvk3ECxbaOH8aA7#P^y*4DOh^XAP- zkdVXd^z`)n_3PIsDe^@DUOEn*&A>mC2(((Nc^csVmzT(&T>5RstJe~!00000NkvXX Hu0mjfM`!{+ literal 0 HcmV?d00001 diff --git a/res/mdpi/drive-harddisk.png b/res/mdpi/drive-harddisk.png new file mode 100644 index 0000000000000000000000000000000000000000..0ae47f104cf430c61905e17566564e6514164f40 GIT binary patch literal 1450 zcmZ9Mc~BBq9LMp96g2TzO}93**4i;#OSaa@nsmhlC6|!0mRxn!^%|8)ge)_&WUO(N z)OOSkFT6<&EAInE&=l{Rbiq;_HIBU2BiLvDv(s;W@A|$s^ZS0@ym=1@9>40tEMO1_ zL?4HBA%YRP({!{z@4|Y>2ZL6WGmfOAqa%|1CI(Ag3ifIgP-#0&~le*lhN$QdwE~^5shohx7XN>)P7d zSFc`WWMn*k{J6EXmCFUmZEFMB2Da+z>KYpxo0^({*xug$WvlJ&+qZl^zoDU_tE;QO zzaN1>SX*18P$;wy+QGpAI0pzsB9TlcdwYBP`uYY11qFu&hlYlRg@uKOhf^q&sHi9^ zl^P9#5ly4fc5&k3;us7DlgUg=OUum6%*x8j&dvtT^YZfY^YZ}|i^VD|EG#N2DlRTA zDJdx}Ed@~J<>i12U;?PBs;XVC>gs9$1?b+qc~etUvkOvRUk^O*;xsomx3si;;oTtx zXgnUTqoV_G2?T=9&Q5>^FuS|EdwP0=LSb)jZ(m;@fE^eZ7#tiN8X6iN9v&GP866!R z8yg!RAD@_*n4FvxiA3+-y_=ev5{tzWiDYJG=KcHkA3l7Tot>SVo0CdsrBdnq{M`Kf z{KCS*;^N}c($dF|i!#}gTrQK#%a9Cz$e7zLj?j&R1tYu}AGHo+%7V|~6D%^!2EGUxfA zR%cYQfsRTe$gGo;lZDPeQ!KQ(zPCQ*L-m-`?FKb#@@sXrb|W)Fmi0yGKDzpxA2gJ9 z>(i%b;-!oD(~MiWEuz#jehW4P^uoa1vZV9k=o*Z6x8m67`LdZRGIrnWw6yq)F3ZI5 z58ad4QgP7(7`0(pNh!AKWbF5Jvq2VO?&w;GE`7$+nEvVdu0MqJSN8@)5tQ4P3Q`YP zqAUv5^)nAXRb6iJ$vDe4&W9IHT9h;$TKdk1W&`OFY=k8a=cH+7o27($oVuSZ=5)5u zgv&##2_^<^4iiwW9BvYE@SjGdz(3FFxWv(tgBAWM@iZgwT*uOGYdKC?>Y9$2i%TV% zRqJJy)`Vb1qN?BpLcMe%v~l-*C-%9e(d6|?oe-6br{c$iD37_Z4N%u8*ZDZSircL#+*+S zP6v6N5W=$~eWsoo1nDJk*ps3gO$6-kr~t%rJ2&U3kFBldploHYpzp9oJ}iAkRTYZ) zS44mE%*m@&8L-0lG)gXBSAAn#UCSOmf8`>d%Gwt`-wXbIv?q?Cv6?%0<$PxCpr%~FBtkbzqzxNz!Qx-ID#=-`sFB@&& oSsBRca9Axy@-5?a;!Gc?A-^a{hT=oGzMYQ`hw*T!aQ033574gW3IG5A literal 0 HcmV?d00001 diff --git a/res/mdpi/drive-optical.png b/res/mdpi/drive-optical.png new file mode 100644 index 0000000000000000000000000000000000000000..74ff49d3c700f741a1823ab6afeba70ef693adf3 GIT binary patch literal 1506 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 literal 0 HcmV?d00001 diff --git a/res/mdpi/folder-bookmark.png b/res/mdpi/folder-bookmark.png new file mode 100644 index 0000000000000000000000000000000000000000..b064712ac3187ad0164170eae9a7f86c8f354c9e GIT binary patch literal 1704 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 Z`+p@?w?NxqYYG4W002ovPDHLkV1n;K43Pi; literal 0 HcmV?d00001 diff --git a/res/mdpi/media-flash-sd-mmc.png b/res/mdpi/media-flash-sd-mmc.png new file mode 100644 index 0000000000000000000000000000000000000000..031240d7a06d3ffa087a0d93d52277b242c90e78 GIT binary patch literal 1709 zcmV;e22%NnP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L05@F#05@F$8GuGz00007bV*G`2iXV> z7cnT&es1Of00u2dL_t(|+O1Y?h?G?ne(rncW5332trS$WP!lyV3;I$wD5D<*h7yAM zryqqPMB+yDBP4>TpfoEC!h(|ek(H2PD2CsaRJvBP>aM1%Yvk^Z+kEWo%=>YB-ZOJ^ zm~i(cy2Ihzd*1h+^PK10bKgPjcxTrc{NLk;)BPB2sCvWOyU!cIzyuTk0k!XQUbO`# ze5^uE2|#mYF7I&3xySkRNiA4BcS7Ie&+nSL;*nXw#?^O31MuXQgT^ft#gPOI7z75& zfIz}|0G~Exl)Mvo0Swo002P9zglm`fhJ-eY@0s7dVfma{&%FB`wye7k^~0$*Xh*?O z)Jn-b<~TB^i5h&yH5_UsqP2rqEVL*+((+C0x!2aa~$*75%FbQpZ?=EGwHFp{JJ zgldohpCXgWT3Aq$rDF(;8-$raM40kI4O8*w`#9Z|p53vn^TgI?7omQ{>J2s^f1-2w zGRoz0we}(1Vy~9y8km40Hs8=Br6Ds8S{jpZe4xAQ^n3tg1E3QTO{)LO7x2}~O94mY zzYL;4`_ms1L;^08;266EFsyqbiGV0P*O%a~>sk>uuDkX;cmM{sY=SS|V86Dp6bcvM~sq9QW6PLTcUap5P{-qu_+ah%N1ck_`a|r+S;rLq)&IkXtKic`RBW#V-0HemX!|yIPzYf!J5fx zbO3Q?adiJ)ULp;qP{^yGE_-Hcb?uy)Iu#H@nM%zG&}m89c05KY9sA_qs0>(V3jnNI z{p!AsTrLZph@-i=MM^O=G=!$6CbCmvi^XJ~$z*H`iqx_Zu>M}TWLCVmE2m=#eDK@@ zYBT`0mM179Ch$676v`td3>V92NG6e_kRg$LJ}+y_0;RSr6`Rr_8*1S4ML;FSK7{MH z9AABpwW#E#nD_OQ448}D8=QF_B-!-%YTf%4ntaDI1PthIOtBYU?|Y^DtZra8pX5DFOU?*+ZrX(yow*RWB@r z8nRDCX26yqocJbO$l87rE@sNIo;1!uZp7g0&S7`~9cf4CF1kj1#5I96CSe3~$QB}= z0k3lSl!Zf@M_kf+wZzO6Cbwy%`#gN!GlI5M5-+U28@WOm2TokVI9|O=?wW?O>q)>J zht5?Gpn!fYl7DVZ1>QvR73`9`j!qDoL|DmMmU@+5zv_>VP{w0SC-Y-^1ro8f4O?;GhL4q;46Z=|$i19+p$V8d)R z0l-{I=K7;R>8m-~6Dc>~`XitmU$*f#eDTs;)Q-OaR4B&UEd?o400000NkvXXu0mjf DI^Qh@ literal 0 HcmV?d00001 diff --git a/res/mdpi/user-home.png b/res/mdpi/user-home.png new file mode 100644 index 0000000000000000000000000000000000000000..d855860b9058fc69d00e671764677dd72a9a5ed9 GIT binary patch literal 1698 zcmV;T23`4yP)Px#32;bRa{vGh*8l(w*8xH(n|J^K00(qQO+^RW1Q`|&DkwDaLI3~&24YJ`L;(K) z{{a7>y{D4^00tsSL_t&-8STN%tEcB(2jJ^_KhN*Xncq6WQDgPO|L zy!zVjfBw14zRk+Ur#|<)`NhxtjBnmL&^rTDQOee;WPQ&IFMcJ{YAR_8aUy7l6G1sK zP$+avh>b-0;q!m|8$bKS*~a1i9shXcrgv}en~H(vL~!ZiX_tTK2Wu{(OhqtH<-XQR zL$$IhQdE^zv?^6hMT)6PugaJI{;QwG7iSy&=+N%%yISwoC=3t0dHvARyK%VZ;Ba5h zP;o3yloLTPVIZNQqZNI`&c*Zf&b2qTY|J*QCj0yQjPAamA!uSrEc^HD?q0R~&UNec zkrIlaVW6C-B5|ycLY$~_efx|%?_FQpm~HIeyW{rmHDe47QOb$f=-s`0w_X3Y*Zt0K z{fc?(ln?e6ium7^|0%vDk<|0IZvFC0vyH3Y_`2OY_hbyJDUo;}u`CC69zAdGkXK)M z+dwPgfvVEbTGRW`MZ-WtJkYAS`R>(E%%A_li?99UPduCTdR@c=<-fbPzxMSvZmC9d zqEJXNxAJ$dzTuniec;D`_(>PeZX1ay1ch>N>E^~543q~N zf;3ju3}q@tNHMkM?cLk{>ZL0lIdj_f=`DZy;@5ot6OVcJnU7i0O-c{(E#Ywgp84qT zP+FNAvC(KK3^W9BA{m0CFjeV2{`#eV_Rg)l9{N zfy-{BaE;f%*bG%;#d#D;d=20fAg|4 z51q2}=y_G4O3;cFqeu}9rQ_lwXFPiDVSo6gmmRIUDJ0BeIJQm{3P*#fk-@+y8b+8} zdHTC|>>V5#A#rRf`asc_Zb{5VlzE;MmJv@q{t>IjI#iey%ZP*oMZ+>kXhjP>R8iIZ z^pAayhfc5j_Mg1y+?n%&1y%IkJ@@QWK6Gx|eK+qN__M!#*}QeeFFf}n4v!XBZ|$2! zPs}!YFrqa^SkS^$jIe}OR9M2B@9jCYnlxp^MjQ)$#L;NJ@y=br!w;>D(D3@ZclACf zjFK=XtXdp|-svcG8)3nOgkYZNoeYu~38A4QVZ9y-Q)5|%N{qw^BTQj!Am${Ng(QL* zYfMUZmmqyq(o0CY@?%42pWQ5RWYVX z4~2n-5k_L3W<%F-YMvwv%=4^OH-$`-Dr)EFe>3OLp0kXhst5xOaiR(#XhjmGJoVT) z?bO3sA_%5dUU}^;b1PN!QNH)Fb5`4Dyz;Ntv{r(tHT!pNns*-A_OZu5N(N#0uUe5f z7F0QwV8j?hSN=oBaQWkxR7fEt(U

$1h17t7_i8`hmIk;oxX(^daRx6%rIeiaDf6 z7{!EvLTto|>MAHIEX9nz?xtd(sySL>{^T<|E%ff)nA3Tu=T zQxWty)-cepYLmBbyl)=L-r>H35mO_WidAtq2!a_$m>PS76@pe&m>YKoL33g*4njlF z3Sn*>9F@YnHMO_i-+lj5O-(g~t%*Ae)yh_}3_4CV`k=zPu^yaWvA?E@)))(E6izh` zJ6kQ5K{dzL1L@9Q*!fDi@BGuhq_u4{8AX+(NOLSjnrNh<3{CYWN=-ub%707*qoM6N<$f&p1a5dZ)H literal 0 HcmV?d00001 diff --git a/src/dlangui/core/files.d b/src/dlangui/core/files.d new file mode 100644 index 00000000..22e8c4f4 --- /dev/null +++ b/src/dlangui/core/files.d @@ -0,0 +1,253 @@ +// Written in the D programming language. + +/** + +This module contains cross-platform file access utilities + + + +Synopsis: + +---- +import dlangui.core.files; +---- + +Copyright: Vadim Lopatin, 2014 +License: Boost License 1.0 +Authors: Vadim Lopatin, coolreader.org@gmail.com +*/ +module dlangui.core.files; + +import std.algorithm; + +private import dlangui.core.logger; +private import std.process; +private import std.path; +private import std.file; +private import std.utf; + +version (Windows) { + /// path delimiter (\ for windows, / for others) + immutable char PATH_DELIMITER = '\\'; +} else { + /// path delimiter (\ for windows, / for others) + immutable char PATH_DELIMITER = '/'; +} + +/// Filesystem root entry / bookmark types +enum RootEntryType : uint { + /// filesystem root + ROOT, + /// current user home + HOME, + /// removable drive + REMOVABLE, + /// fixed drive + FIXED, + /// network + NETWORK, + /// cd rom + CDROM, + /// sd card + SDCARD, + /// custom bookmark + BOOKMARK, +} + +/// Filesystem root entry item +struct RootEntry { + private RootEntryType _type; + private string _path; + private dstring _display; + this(RootEntryType type, string path, dstring display = null) { + _type = type; + _path = path; + _display = display; + if (display is null) { + _display = toUTF32(baseName(path)); + } + } + /// Returns type + @property RootEntryType type() { return _type; } + /// Returns path + @property string path() { return _path; } + /// Returns display label + @property dstring label() { return _display; } + /// Returns icon resource id + @property string icon() { + switch (type) { + case RootEntryType.NETWORK: + return "folder-network"; + case RootEntryType.BOOKMARK: + return "folder-bookmark"; + case RootEntryType.CDROM: + return "drive-optical"; + case RootEntryType.FIXED: + return "drive-harddisk"; + case RootEntryType.HOME: + return "user-home"; + case RootEntryType.ROOT: + return "computer"; + case RootEntryType.SDCARD: + return "media-flash-sd-mmc"; + case RootEntryType.REMOVABLE: + return "device-removable-media"; + default: + return "folder-blue"; + } + } +} + +/// Returns +@property RootEntry homeEntry() { + return RootEntry(RootEntryType.HOME, homePath); +} + +/// returns array of system root entries +@property RootEntry[] getRootPaths() { + RootEntry[] res; + res ~= RootEntry(RootEntryType.HOME, homePath); + version (posix) { + res ~= RootEntry(RootEntryType.ROOT, "/", "File System"d); + } + version (Windows) { + import win32.windows; + uint mask = GetLogicalDrives(); + for (int i = 0; i < 26; i++) { + if (mask & (1 << i)) { + char letter = cast(char)('A' + i); + string path = "" ~ letter ~ ":\\"; + dstring display = ""d ~ letter ~ ":"d; + // detect drive type + RootEntryType type; + uint wtype = GetDriveTypeA(("" ~ path).ptr); + //Log.d("Drive ", path, " type ", wtype); + switch (wtype) { + case DRIVE_REMOVABLE: + type = RootEntryType.REMOVABLE; + break; + case DRIVE_REMOTE: + type = RootEntryType.NETWORK; + break; + case DRIVE_CDROM: + type = RootEntryType.CDROM; + break; + default: + type = RootEntryType.FIXED; + break; + } + res ~= RootEntry(type, path, display); + } + } + } + return res; +} + +/** Returns true if char ch is / or \ slash */ +bool isPathDelimiter(char ch) { + return ch == '/' || ch == '\\'; +} + +/** Returns current executable path only, including last path delimiter - removes executable name from result of std.file.thisExePath() */ +@property string exePath() { + string path = thisExePath(); + int lastSlash = 0; + for (int i = 0; i < path.length; i++) + if (path[i] == PATH_DELIMITER) + lastSlash = i; + return path[0 .. lastSlash + 1]; +} + +/// Returns user's home directory +@property string homePath() { + string path; + version (Windows) { + path = environment.get("USERPROFILE"); + if (path is null) + path = environment.get("HOME"); + } else { + path = environment.get("HOME"); + } + if (path is null) + path = "."; // fallback to current directory + return path; +} + +/** + + Returns application data directory + + On unix, it will return path to subdirectory in home directory - e.g. /home/user/.subdir if ".subdir" is passed as a paramter. + + On windows, it will return path to subdir in APPDATA directory - e.g. C:\Users\User\AppData\Roaming\.subdir. + + */ +string appDataPath(string subdir = null) { + string path; + version (Windows) { + path = environment.get("APPDATA"); + } + if (path is null) + path = homePath; + if (subdir !is null) { + path ~= PATH_DELIMITER; + path ~= subdir; + } + return path; +} + +/// Converts path delimiters to standard for platform inplace in buffer(e.g. / to \ on windows, \ to / on posix), returns buf +char[] convertPathDelimiters(char[] buf) { + foreach(ref ch; buf) { + version (Windows) { + if (ch == '/') + ch = '\\'; + } else { + if (ch == '\\') + ch = '/'; + } + } + return buf; +} + +/** Converts path delimiters to standard for platform (e.g. / to \ on windows, \ to / on posix) */ +string convertPathDelimiters(string src) { + char[] buf = src.dup; + return cast(string)convertPathDelimiters(buf); +} + +/** Appends file path parts with proper delimiters e.g. appendPath("/home/user", ".myapp", "config") => "/home/user/.myapp/config" */ +string appendPath(string[] pathItems ...) { + char[] buf; + foreach (s; pathItems) { + if (buf.length && !isPathDelimiter(buf[$-1])) + buf ~= PATH_DELIMITER; + buf ~= s; + } + return convertPathDelimiters(buf).dup; +} + +/** Appends file path parts with proper delimiters (as well converts delimiters inside path to system) to buffer e.g. appendPath("/home/user", ".myapp", "config") => "/home/user/.myapp/config" */ +char[] appendPath(char[] buf, string[] pathItems ...) { + foreach (s; pathItems) { + if (buf.length && !isPathDelimiter(buf[$-1])) + buf ~= PATH_DELIMITER; + buf ~= s; + } + return convertPathDelimiters(buf); +} + +/** Split path into elements, e.g. /home/user/dir1 -> ["home", "user", "dir1"], "c:\dir1\dir2" -> ["c:", "dir1", "dir2"] */ +string[] splitPath(string path) { + string[] res; + int start = 0; + for (int i = 0; i <= path.length; i++) { + char ch = i < path.length ? path[i] : 0; + if (ch == '\\' || ch == '/' || ch == 0) { + if (start < i) + res ~= path[start .. i].dup; + start = i + 1; + } + } + return res; +} diff --git a/src/dlangui/dialogs/filedlg.d b/src/dlangui/dialogs/filedlg.d index 88475cef..2c46e0ac 100644 --- a/src/dlangui/dialogs/filedlg.d +++ b/src/dlangui/dialogs/filedlg.d @@ -48,23 +48,54 @@ enum FileDialogFlag : uint { Save = ConfirmOverwrite, } -/// file open / save dialog +/// File open / save dialog class FileDialog : Dialog { - EditLine path; - StringGridWidget list; - StringGridWidget places; - VerticalLayout leftPanel; - VerticalLayout rightPanel; + protected EditLine path; + protected EditLine filename; + protected StringGridWidget list; + //protected StringGridWidget places; + protected VerticalLayout leftPanel; + protected VerticalLayout rightPanel; + + protected RootEntry[] _roots; + this(UIString caption, Window parent, uint fileDialogFlags = DialogFlag.Modal | FileDialogFlag.FileMustExist) { super(caption, parent, fileDialogFlags); } + + protected void rootEntrySelected(RootEntry entry) { + // TODO + } + + protected Widget createRootsList() { + ListWidget list = new ListWidget("ROOTS_LIST"); + WidgetListAdapter adapter = new WidgetListAdapter(); + foreach(ref RootEntry root; _roots) { + ImageTextButton btn = new ImageTextButton(null, root.icon, root.label); + btn.orientation = Orientation.Vertical; + btn.styleId = "TRANSPARENT_BUTTON_BACKGROUND"; + btn.focusable = false; + btn.onClickListener = delegate(Widget source) { + rootEntrySelected(root); + return true; + }; + adapter.widgets.add(btn); + } + list.ownAdapter = adapter; + list.layoutWidth = WRAP_CONTENT; + list.layoutHeight = FILL_PARENT; + return list; + } + /// override to implement creation of dialog controls override void init() { + _roots = getRootPaths; layoutWidth(FILL_PARENT); layoutWidth(FILL_PARENT); LinearLayout content = new HorizontalLayout("dlgcontent"); content.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT).minWidth(400).minHeight(300); leftPanel = new VerticalLayout("places"); + leftPanel.addChild(createRootsList()); rightPanel = new VerticalLayout("main"); leftPanel.layoutHeight(FILL_PARENT).minWidth(40); rightPanel.layoutHeight(FILL_PARENT).layoutWidth(FILL_PARENT); @@ -73,6 +104,8 @@ class FileDialog : Dialog { content.addChild(rightPanel); path = new EditLine("path"); path.layoutWidth(FILL_PARENT); + filename = new EditLine("path"); + filename.layoutWidth(FILL_PARENT); rightPanel.addChild(path); list = new StringGridWidget("files"); @@ -84,12 +117,13 @@ class FileDialog : Dialog { list.showRowHeaders = false; list.rowSelect = true; rightPanel.addChild(list); + rightPanel.addChild(filename); - places = new StringGridWidget("placesList"); - places.resize(1, 10); - places.showRowHeaders(false).showColHeaders(true); - places.setColTitle(0, "Places"d); - leftPanel.addChild(places); + //places = new StringGridWidget("placesList"); + //places.resize(1, 10); + //places.showRowHeaders(false).showColHeaders(true); + //places.setColTitle(0, "Places"d); + //leftPanel.addChild(places); addChild(content); addChild(createButtonsPanel([ACTION_OPEN, ACTION_CANCEL], 0, 0)); diff --git a/src/dlangui/widgets/controls.d b/src/dlangui/widgets/controls.d index 02679334..bec72a3e 100644 --- a/src/dlangui/widgets/controls.d +++ b/src/dlangui/widgets/controls.d @@ -207,14 +207,40 @@ class ImageButton : ImageWidget { class ImageTextButton : HorizontalLayout { protected ImageWidget _icon; protected TextWidget _label; + + /// Get label text override @property dstring text() { return _label.text; } + /// Set label plain unicode string override @property Widget text(dstring s) { _label.text = s; requestLayout(); return this; } + /// Set label string resource Id override @property Widget text(UIString s) { _label.text = s; requestLayout(); return this; } - this(string ID = null, string drawableId = null, string textResourceId = null) { - super(ID); + + /// Returns orientation: Vertical - image top, Horizontal - image left" + override @property Orientation orientation() { + return super.orientation(); + } + + /// Sets orientation: Vertical - image top, Horizontal - image left" + override @property LinearLayout orientation(Orientation value) { + if (!_icon || !_label) + return super.orientation(value); + if (value != orientation) { + super.orientation(value); + if (value == Orientation.Horizontal) { + _icon.alignment = Align.Left | Align.VCenter; + _label.alignment = Align.Right | Align.VCenter; + } else { + _icon.alignment = Align.Top | Align.HCenter; + _label.alignment = Align.Bottom | Align.HCenter; + } + } + return this; + } + + protected void init(string drawableId, UIString caption) { styleId = "BUTTON"; _icon = new ImageWidget("icon", drawableId); - _label = new TextWidget("label", textResourceId); + _label = new TextWidget("label", caption); _label.styleId = "BUTTON_LABEL"; _icon.state = State.Parent; _label.state = State.Parent; @@ -224,20 +250,17 @@ class ImageTextButton : HorizontalLayout { focusable = true; trackHover = true; } + + this(string ID = null, string drawableId = null, string textResourceId = null) { + super(ID); + UIString caption = textResourceId; + init(drawableId, caption); + } + this(string ID, string drawableId, dstring rawText) { super(ID); - styleId = "BUTTON"; - _icon = new ImageWidget("icon", drawableId); - _label = new TextWidget("label", rawText); - _label.styleId = "BUTTON_LABEL"; - _icon.styleId = "BUTTON_ICON"; - _icon.state = State.Parent; - _label.state = State.Parent; - addChild(_icon); - addChild(_label); - clickable = true; - focusable = true; - trackHover = true; + UIString caption = rawText; + init(drawableId, caption); } } diff --git a/src/dlangui/widgets/lists.d b/src/dlangui/widgets/lists.d index 69b29c05..d50b236d 100644 --- a/src/dlangui/widgets/lists.d +++ b/src/dlangui/widgets/lists.d @@ -38,7 +38,7 @@ interface ListAdapter { /// List adapter for simple list of widget instances class WidgetListAdapter : ListAdapter { - WidgetList _widgets; + private WidgetList _widgets; /// list of widgets to display @property ref WidgetList widgets() { return _widgets; } /// returns number of widgets in list