From 4c4846e4a7883286413811c0d45004f4ad41ed6e Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Thu, 17 Apr 2014 16:17:58 +0400 Subject: [PATCH] implement CheckBox and RadioButton controls --- .gitignore | 7 +- README.md | 4 + dlanguilib.visualdproj | 6 +- examples/example1/src/main.d | 18 ++- examples/helloworld/src/app.d | 6 +- res/btn_check.xml | 65 ++++++++++ res/btn_radio.xml | 59 ++++++++++ res/btn_radio_background.xml | 11 ++ ..._check_off_disabled_focused_holo_light.png | Bin 0 -> 368 bytes .../btn_check_off_disabled_holo_light.png | Bin 0 -> 329 bytes res/mdpi/btn_check_off_focused_holo_light.png | Bin 0 -> 425 bytes res/mdpi/btn_check_off_holo_light.png | Bin 0 -> 323 bytes res/mdpi/btn_check_off_normal_holo_light.png | Bin 0 -> 491 bytes res/mdpi/btn_check_off_pressed_holo_light.png | Bin 0 -> 1598 bytes ...n_check_on_disabled_focused_holo_light.png | Bin 0 -> 632 bytes res/mdpi/btn_check_on_disabled_holo_light.png | Bin 0 -> 508 bytes res/mdpi/btn_check_on_focused_holo_light.png | Bin 0 -> 1749 bytes res/mdpi/btn_check_on_holo_light.png | Bin 0 -> 1529 bytes res/mdpi/btn_check_on_pressed_holo_light.png | Bin 0 -> 1907 bytes ..._radio_off_disabled_focused_holo_light.png | Bin 0 -> 919 bytes .../btn_radio_off_disabled_holo_light.png | Bin 0 -> 479 bytes res/mdpi/btn_radio_off_focused_holo_light.png | Bin 0 -> 1046 bytes res/mdpi/btn_radio_off_holo_light.png | Bin 0 -> 533 bytes res/mdpi/btn_radio_off_pressed_holo_light.png | Bin 0 -> 1834 bytes ...n_radio_on_disabled_focused_holo_light.png | Bin 0 -> 1272 bytes res/mdpi/btn_radio_on_disabled_holo_light.png | Bin 0 -> 736 bytes res/mdpi/btn_radio_on_focused_holo_light.png | Bin 0 -> 1403 bytes res/mdpi/btn_radio_on_holo_light.png | Bin 0 -> 578 bytes res/mdpi/btn_radio_on_pressed_holo_light.png | Bin 0 -> 1300 bytes src/dlangui/all.d | 5 + src/dlangui/graphics/resources.d | 20 +++- src/dlangui/platforms/windows/win32fonts.d | 6 +- src/dlangui/widgets/controls.d | 111 +++++++++++++++++- src/dlangui/widgets/styles.d | 25 +++- src/dlangui/widgets/widget.d | 43 ++++++- 35 files changed, 355 insertions(+), 31 deletions(-) create mode 100644 res/btn_check.xml create mode 100644 res/btn_radio.xml create mode 100644 res/btn_radio_background.xml create mode 100644 res/mdpi/btn_check_off_disabled_focused_holo_light.png create mode 100644 res/mdpi/btn_check_off_disabled_holo_light.png create mode 100644 res/mdpi/btn_check_off_focused_holo_light.png create mode 100644 res/mdpi/btn_check_off_holo_light.png create mode 100644 res/mdpi/btn_check_off_normal_holo_light.png create mode 100644 res/mdpi/btn_check_off_pressed_holo_light.png create mode 100644 res/mdpi/btn_check_on_disabled_focused_holo_light.png create mode 100644 res/mdpi/btn_check_on_disabled_holo_light.png create mode 100644 res/mdpi/btn_check_on_focused_holo_light.png create mode 100644 res/mdpi/btn_check_on_holo_light.png create mode 100644 res/mdpi/btn_check_on_pressed_holo_light.png create mode 100644 res/mdpi/btn_radio_off_disabled_focused_holo_light.png create mode 100644 res/mdpi/btn_radio_off_disabled_holo_light.png create mode 100644 res/mdpi/btn_radio_off_focused_holo_light.png create mode 100644 res/mdpi/btn_radio_off_holo_light.png create mode 100644 res/mdpi/btn_radio_off_pressed_holo_light.png create mode 100644 res/mdpi/btn_radio_on_disabled_focused_holo_light.png create mode 100644 res/mdpi/btn_radio_on_disabled_holo_light.png create mode 100644 res/mdpi/btn_radio_on_focused_holo_light.png create mode 100644 res/mdpi/btn_radio_on_holo_light.png create mode 100644 res/mdpi/btn_radio_on_pressed_holo_light.png diff --git a/.gitignore b/.gitignore index dc269a50..863ad45e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,10 @@ Debug Release +Unittest ui.log obj - +*.suo +Thumbs.db +.dub +bin +*.obj diff --git a/README.md b/README.md index 9264bbdd..ce90255d 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ Hello World // setup resource directories - will use only existing directories drawableCache.setResourcePaths(resourceDirs); + // optinally setup internatilnalization (if used) // setup i18n - look for i18n directory inside one of passed directories i18n.findTranslationsDir(resourceDirs); // select translation file - for english language @@ -72,7 +73,10 @@ Hello World // create window Window window = Platform.instance.createWindow("My Window", null); + // create some widget to show in window window.mainWidget = (new Button()).text("Hello world"d); + // show window + window.show(); // run message loop return Platform.instance.enterMessageLoop(); } diff --git a/dlanguilib.visualdproj b/dlanguilib.visualdproj index 2d9c732d..68797e73 100644 --- a/dlanguilib.visualdproj +++ b/dlanguilib.visualdproj @@ -54,12 +54,12 @@ 0 - - + docs + docs/index.html 0 - + include 1 $(IntDir)\$(TargetName).json diff --git a/examples/example1/src/main.d b/examples/example1/src/main.d index 34e75830..c132388b 100644 --- a/examples/example1/src/main.d +++ b/examples/example1/src/main.d @@ -12,8 +12,10 @@ extern (C) int UIAppMain(string[] args) { // resource directory search paths string[] resourceDirs = [ appendPath(exePath, "../../../res/"), // for Visual D and DUB builds + appendPath(exePath, "../../../res/mdpi/"), // for Visual D and DUB builds appendPath(exePath, "../../../../res/"),// for Mono-D builds - appendPath(exePath, "res/") // when res dir is located at the same directory as executable + appendPath(exePath, "../../../../res/mdpi/"),// for Mono-D builds + appendPath(exePath, "res/mdpi/") // when res dir is located at the same directory as executable ]; // setup resource directories - will use only existing directories drawableCache.setResourcePaths(resourceDirs); @@ -70,9 +72,9 @@ extern (C) int UIAppMain(string[] args) { LinearLayout hlayout = new HorizontalLayout(); //hlayout.addChild((new Button()).text("<<")); //.textColor(0x40FF4000) hlayout.addChild((new TextWidget()).text("Several").alignment(Align.Center)); - hlayout.addChild((new ImageWidget()).drawableId("exit").padding(Rect(5,5,5,5)).alignment(Align.Center)); + hlayout.addChild((new ImageWidget()).drawableId("btn_radio").padding(Rect(5,5,5,5)).alignment(Align.Center)); hlayout.addChild((new TextWidget()).text("items").alignment(Align.Center)); - hlayout.addChild((new ImageWidget()).drawableId("exit").padding(Rect(5,5,5,5)).alignment(Align.Center)); + hlayout.addChild((new ImageWidget()).drawableId("btn_check").padding(Rect(5,5,5,5)).alignment(Align.Center)); hlayout.addChild((new TextWidget()).text("in horizontal layout")); hlayout.addChild((new ImageWidget()).drawableId("exit").padding(Rect(5,5,5,5)).alignment(Align.Center)); //hlayout.addChild((new Button()).text(">>")); //.textColor(0x40FF4000) @@ -84,6 +86,9 @@ extern (C) int UIAppMain(string[] args) { vlayout.addChild((new TextWidget()).text("VLayout line 1").textColor(0x40FF4000)); // vlayout.addChild((new TextWidget()).text("VLayout line 2").textColor(0x40FF8000)); vlayout.addChild((new TextWidget()).text("VLayout line 2").textColor(0x40008000)); + vlayout.addChild(new RadioButton("rb1", "Radio button 1"d)); + vlayout.addChild(new RadioButton("rb2", "Radio button 2"d)); + vlayout.addChild(new RadioButton("rb3", "Radio button 3"d)); vlayout.layoutWidth(FILL_PARENT); vlayoutgroup.addChild(vlayout); vlayoutgroup.layoutWidth(FILL_PARENT); @@ -94,12 +99,13 @@ extern (C) int UIAppMain(string[] args) { ScrollBar sb = new ScrollBar("hscroll", Orientation.Horizontal); layout.addChild(sb.layoutHeight(WRAP_CONTENT).layoutWidth(FILL_PARENT)); - layout.addChild((new Button("BTN2")).textColor(0x000000FF).text("Button2")); + layout.addChild((new CheckBox("BTN2", "Some checkbox"d))); layout.addChild((new TextWidget()).textColor(0x40FF4000).text("Text widget")); layout.addChild((new ImageWidget()).drawableId("exit").padding(Rect(5,5,5,5))); layout.addChild((new TextWidget()).textColor(0xFF4000).text("Text widget2").padding(Rect(5,5,5,5)).margins(Rect(5,5,5,5)).backgroundColor(0xA0A0A0)); - layout.addChild((new Button("BTN3")).textColor(0x000000FF).text("Button3").layoutHeight(FILL_PARENT)); - layout.addChild((new TextWidget()).textColor(0x004000).text("Text widget3 with very long text")); + layout.addChild((new RadioButton("BTN3", "Some radio button"d))); + layout.addChild((new TextWidget(null, "Text widget3 with very long text"d)).textColor(0x004000)); + layout.addChild(new VSpacer()); // vertical spacer to fill extra space layout.childById("BTN1").onClickListener = (delegate (Widget w) { Log.d("onClick ", w.id); return true; }); layout.childById("BTN2").onClickListener = (delegate (Widget w) { Log.d("onClick ", w.id); return true; }); diff --git a/examples/helloworld/src/app.d b/examples/helloworld/src/app.d index b33b09b1..f60a5202 100644 --- a/examples/helloworld/src/app.d +++ b/examples/helloworld/src/app.d @@ -25,10 +25,12 @@ extern (C) int UIAppMain(string[] args) { // create window Window window = Platform.instance.createWindow("My Window", null); - window.mainWidget = (new Button()).text("sample button"); + // create some widget to show in window + window.mainWidget = (new Button()).text("Hello world"d); + // show window window.show(); - //window.windowCaption = "New Window Caption"; + // run message loop return Platform.instance.enterMessageLoop(); } diff --git a/res/btn_check.xml b/res/btn_check.xml new file mode 100644 index 00000000..c8c2bee0 --- /dev/null +++ b/res/btn_check.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/btn_radio.xml b/res/btn_radio.xml new file mode 100644 index 00000000..e2f1f84c --- /dev/null +++ b/res/btn_radio.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/btn_radio_background.xml b/res/btn_radio_background.xml new file mode 100644 index 00000000..005b6fc7 --- /dev/null +++ b/res/btn_radio_background.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/res/mdpi/btn_check_off_disabled_focused_holo_light.png b/res/mdpi/btn_check_off_disabled_focused_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..42442e8fea130bb8bdb377e2ea70eaff5d976f99 GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvtpJ}8S0K$W^9&kdoPLtCZ39=! zT4OMP$o{z1unMS{uO!GXn1O|x**YrPN=w^B+bVKy#fpDG8O{Qa$YLPv0mg18v+aNk zZ%-G;5RLQ62@3=Tf|{6IIp*Iq<>hkXIl$!eaIW#e1h9nO2Eg!;zMn0H6j*kPX54 rX(i=}MX3yqDfvmM3ZA)%>8U}fi7AzZCsS>JiWody{an^LB{Ts5Dz9)! literal 0 HcmV?d00001 diff --git a/res/mdpi/btn_check_off_disabled_holo_light.png b/res/mdpi/btn_check_off_disabled_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..db190430ce0a5e6daeec894453fcddc6e8fa5adc GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(eqE(mY)pLp+WrCrGd!W-wS()GH}@a>QWZRN c6Vp?JQWH}u3s0un02MKKy85}Sb4q9e0K-jeO#lD@ literal 0 HcmV?d00001 diff --git a/res/mdpi/btn_check_off_focused_holo_light.png b/res/mdpi/btn_check_off_focused_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..3fc71fd2032331ac67a89ffee690e7aa8ed1fe31 GIT binary patch literal 425 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyHUT~%u0Wb$<{A8mar#N_=GD9n z%M7e+4b83Kiv7G~I)K_mN`m}?85kIunEB-t6qCBT(<34#lq7WW-CbC787R+L;1O92 zq&>jc?PRtckdfo*;uvCa`t2l3z5@z8EC&;KX3YNo-&EC|>y%2+vacfAl`R$ALJqkM zCtj|*I3ZS{xk{qp+~>A(4rc?qBU=QT&7A{|7*21MnR!J(XZfacdYy0eYl1EI{+8fL z$gM6~>vz)g?)!^nw&}Ge{w3;N%HxyGuKy(pv{$vnHKHUXu_Vl&C_85nH6dE^a>hTQy=%(P0}8jiHo1OPQif@}!RPb(=;EJ|f? jOvz75Rq)JBOiv9;O-!jQJeg_(RK(!v>gTe~DWM4fvPg{W literal 0 HcmV?d00001 diff --git a/res/mdpi/btn_check_off_holo_light.png b/res/mdpi/btn_check_off_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..5e04a57b58ea0a7a3982aa55b5fa324b0ddbffc7 GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(eqE5MRLZ+75`6v`1dA0g;C6ewTb5`&-o7$ z3P&%T{J=J!@eI%TbKf3c%a7@JXQ$?MIN?e|AhR291H+d)Kc+jL+9A+irP;QB1(S%l z#^Qts28QgD0#Ah6bu)l=sg}4#l%ynCtjXA}~ zdDB%)JN%#dR3xZ{h5xp?HZ^bY)V{6x){+JfSE(#tWBACU@WYv{dup%OEPZd;I!ByI z$WddSqOHZsdtaoDnN%B3XKZ7=y!CwV`XBe34=HA{C@ph$=YGYfbg^*v<8sM=+3K5& zmrYGL>!b4O$h!ZZ|1W9vnW8kyv(d~+M22&{>1u_@+1DjhKAdwswV_axk-LfaWJS`G zOL4^h@qL4p^25Lsjh*!m4U&v4IP{)8glbfGSez?Ygqo)U@K6AB*=!~ r{Irtt#G+IN$CUh}R0Yr6#Prml)Wnp^!jq{sKt&9mu6{1-oD!M4KS{3se9@Ky!d*f=qyk=xut04L#P|gazquehfz-1sfjd zFFdV3|D^tclllu!p(CImP-@|6pfbal9K+07!>l?msyEE4H_V2h2DpI`h5?clP^kqc zfp!7K!RQG{!Gco;n}G}{0-6R?3F2-6BRB)XMIsHe8-R{9-0}pd9^{^w9Q}o7fX;)4 zGdQ%_k35(SjEuUHAirQikCe=uy!^uA(z5c3%Brf8qJq4vR8Oz;>e{-RT<@~_hQ_Am zme#iRj?S*`o{ql$36myInL4p+>de`5=Py{eXx^Mz)4IoKFVa%%CG8Ar}e@5xTf@M1Q|0j38A&H|6f zVj%4S#%?FG?HCxCBRyRlLo81FPW~NzD?*^{eBMr0k5gyYc{)sT@HoMG=xpxZ#B6R2 zFK)+7PY*>A!GJBBZohr??*BgFocZbd-j&kH(4-N^|Akr z(2(iel_ae%@GDpN(L{r1{6Z?O>s^m>+BE#!bI~QIm^;^|*mdu|lnEV|c}_3A^fII? zIkSuBmvf@O(zeDq6({y!7;8TKK7D;z+4pb!tFFE}c<e0WK6-xs z@@7lrofX&b$)0qYrN}JN#G*4lH12BDd;2ZcRx7IOF8+@AePz0lOs~42iU(&=-SU6` z7A=;3mXIJ7w*Btv`fDN=JsX)+4yRu|l=s;AxKX?EZMj}{x9^WmKRn{;_)x=Rqoij1 z9qYW;&u;9S|LEvGK+m_)24sRj9<>#ReNK{3#sOf zwzF?8Ubt|3|M#v+&jL2lf>{%`UjG`mJ9}pH!-5Q{UzO`Oawj*)HFF$JoMQRa_iZx& zw8Y4^rRBHw+V6k+B$ZL?MW&a#G=@*oM`j#xl&Thvc4gwQXeZ-2Adf<7Afn60M-H2bNZHKEEEkN#^7iU^!aQ zkWxHp%IPj9i*_|dxkCE|yzLyU1(VVaRM=>|tvGKuO}O4AdbUG_v!{c`ti*_Ei89~U zt$kVdBb|Gpc>hKhkvF^?j>jBT9{#xh{Huzb+<({qj7#4g4SgiFAQ+h2R7+eVN>UO_ zQmvAUQh^kMk%6J1uAzahkwu81v6YFDm4Uggfw`4|!Pc8c-k@m6%}>cptHiD0NJ~us xP=h4MhT#0PlJdl&R0hYC{G?O`&)mfH)S%SFl*+=BsWw1G44$rjF6*2UngD^R1mOSx literal 0 HcmV?d00001 diff --git a/res/mdpi/btn_check_on_disabled_focused_holo_light.png b/res/mdpi/btn_check_on_disabled_focused_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..997045de11d7bdb48ac870f94ee5dd3abf33e123 GIT binary patch literal 632 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dylLLH0T!A#h%rjUK7k1uC$m48W~`8^b#3Ae@cN&{tn{1L!Klk|4ie24*g9MvKVkKr1b66&6-~0TXRm z$Lg4dIwwYl`e=T8W)?ef8;%-VK2?s0sM<&#?i~N7Pe9F_1s;*bK-vS0-A-oP0U5_V zT^vI!PG7xrQ>aNnf;HjFl@=wHiD&M9JNoMHe7)&842x&#S(l&r*^u~y@yC3LWva*K ztl0Z@N7AxoOghJ#Jx=8GiMufAeOWm{l`q0WrD4U6g)e_jEBhJxwEw&_zde`hRL1$D7`a{lDvESP=jd~$J68WUWftjWR7gDZde>|FX1_0c z*|sctU&=7y%eDRf><9ib?rT=u&-`<@=GTQhQyLvPs`@ytOw4|Cqpf18(U!M&q#o3N zV#%H(5*;{)LkH+3)e_f;l9a@fRIB8oR3OD*WMF8hYiOWrWD#O$Xk~0}Wn!XhU~Xk# zu-npU4H5f8mH{gTe~DWM4fvSild literal 0 HcmV?d00001 diff --git a/res/mdpi/btn_check_on_disabled_holo_light.png b/res/mdpi/btn_check_on_disabled_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..20e2aab12b39cd77efd3a0ab36420a9e123cd181 GIT binary patch literal 508 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(i1-V3hQ9aSZV|{&vbnzrzM1uKuqgF33M%me3TAo@?_@Qqv=c$3H2#d8vuV zU8`lHD@0b#SeU!$(v99DO#$zxSiG09zwP;8M*W18?_olIb$wSOUoMZ(n~@Gelm-xpUX%JwH0>@rF6Ys^4E-U%Yo+wy1a8;YXU4cOK1UO)5-@uu0~c zYwF*`WSI2o^%TWQX*rP&*Aqwb3fi|k{ylrg+`xhgp~?fsIR$$pVr4}p6tyWTE*qvD{bC>mF=5@HkX$ToA6=fZh6cJu79oa)R>tO5CMLQD=2iv<>rHpFqiD#@ zPsvQHMAu+uWo!h|5V1dG8Bl{H$cEtjw370~qErUQl>DSr1<%~X^wgl##FWaylc_d9 OMGT&8K^-J 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 O7{SijR&eZW^8W$cRG5eW literal 0 HcmV?d00001 diff --git a/res/mdpi/btn_radio_off_disabled_focused_holo_light.png b/res/mdpi/btn_radio_off_disabled_focused_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..4dac84cfe88b74e18f5c12c664fa8d0fb4f067dc GIT binary patch literal 919 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabRA=0VB`q!32_B-jki9vwY3G36rs(J zt-}(4=D>k2)%A8^bx*T%43W8i5dYtlX zoDLj}5*&^JoLa)NBHo;=I-H&Y$|`))!je2%-13|vK^z=PoIqe0%X#;$=wqPSoCO|{ z#X#BvjNMLV+W{lP%hSa%#NzbXNzu_w4gzhgA|>IBis7xMhAc)s3TICBl`LsaRsa3} zzseiUNP*Xzp5>M8pF4Nv`?F8~g$MZTJFuzM#yK^<_^41rU_;Q%(-T4}7`s9}r-iRl z61m~^Yu?I*Rf|`ykk~%u>b4FOwXgfytg@@F8|a=k+4ZZ6KeJOxq~A*V#=Fa#Ti!`m zY;KR(#P3(IZNsCwwkb~ICJ#)@MpJaZMC{J3f~K5(BnyFj*Y-vZqt?;U*`p8s5W<9}=ogNu@; zWkX^00buZ|mbgZgq$HN4S|t~y0x1R~14BbyLjzqSix5L&D`OKYQxjbSb1MUb7hkqs zMA49&pOTqYiCe?WmAtt?4U!-mg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+5ik4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(eqE{&>1LhIkx*J7sUyVFQs?d-G1#V|{l|E|FtuwP~9d*B|&|!ofDaquVYu zOmVO}BB>Oe@Y*qoSwcY z*?cCCgWA#=2StI-;xQwB6k(#>zi%16Fj}nLA7DmmzpMHscS(4arKwy$0A9J0qc*0$8skax} z7-ud0vP(7P&7p>}AO9~$ZCJv~%p*H>j-Q8%>5{|z0T(6&^a&a*Qdw9i|MUN0mioTW z7e3nrBpq1vm-*?!-51P_MT7Moc8B!>!$GygHKHUXu_V8e=o*+?85q3yvh^a0hTQy=%(P0}8fLEK%>`VPV3{6dk%tpmb=f|eOoa6yD=n;t*};a1pq z1;CZr_yoaKLX{zT8LkYX2Ce|e0E&RfjUdB;Y|HctAj3K^0_Z#-0|+ehntf?Ba55 z#gw`{yj=tXD#CQ7r1ks+UB!Y0LUKeC1oN2elPc_GgM8&|3dGC!_(c=NO#*F9+cabo zbYj$m@@4d6*-K@a1q2I3g+l#>JjLS0s^$JHJz@{Emb1VkvKUBvfU(=jY&&4Y$9lRr zhFF|VPLPOcm^ia_YH#n<)|rC4O|03~#m)Ko&BgWQ?Zs4?nw;(&Qd*SsXpxf8ok>BL zUVJ)Zw5jM5SC`kRQ(juDvJSnHI+O9sG}@dYkaTXoN)J`UP^NI@(ljRx2z*(T3CHlmV9vL>7vJ3{Q?`z%Zs0Xa*#Oq zCiC&rx6L`r*KeP1uYYJRV@xBTqt6Mh8E2ZEogyFHF_`zE!y_bL(zW%o%i+o(8^euk zE4Uu5IkMxC@qbfE!hn8!I!Tkn~RGsE|Qjzoppd^^70w^>C2Zy zDCq0V?w*$5;JI$XZM7vHK0YQ#=0|fFpKKIbyIEc3V$r9Kk3FuRVO$dwWHI^g0Y-+i zaTe1;MTBnvLtM4QHKHUXu_V8e=o*+?85q3y zvh^a0hTQy=%(P0}8fLEK%>`k4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(i1-U^Mb{aSZV|{&vcKufq-u?faKJ2r{^;!{v0#!+Z4)4s(vH2i-4R{9bhV zBKw3iEBOOU>kY1WDCKebx{5C>+%&G^I;#j($q-Jncl_Pij zv~Q|EOujO8v&eGt?tO57MN>$vN~>(pUWEm^UbmU7SgHqq_ysPFroVA-1Fi6FT2cbf>M2c-wBft)_HD|>cn&7OM#^E z3XAlJIt^W&gk#!=H}R()j{3lS%_mC7en&+VFc?)!Tq8R literal 0 HcmV?d00001 diff --git a/res/mdpi/btn_radio_off_pressed_holo_light.png b/res/mdpi/btn_radio_off_pressed_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..2a7d0d5227a033e32af1b47017622ac00143205c GIT binary patch literal 1834 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 literal 0 HcmV?d00001 diff --git a/src/dlangui/all.d b/src/dlangui/all.d index bdb984fa..1f7495be 100644 --- a/src/dlangui/all.d +++ b/src/dlangui/all.d @@ -21,8 +21,10 @@ extern (C) int UIAppMain(string[] args) { appendPath(exePath, "../../../../res/"), // for Mono-D builds appendPath(exePath, "res/") // when res dir is located at the same directory as executable ]; + // setup resource directories - will use only existing directories drawableCache.setResourcePaths(resourceDirs); + // setup i18n - look for i18n directory inside one of passed directories i18n.findTranslationsDir(resourceDirs); // select translation file - for english language @@ -30,7 +32,10 @@ extern (C) int UIAppMain(string[] args) { // create window Window window = Platform.instance.createWindow("My Window", null); + // create some widget to show in window window.mainWidget = (new Button()).text("Hello world"d); + // show window + window.show(); // run message loop return Platform.instance.enterMessageLoop(); } diff --git a/src/dlangui/graphics/resources.d b/src/dlangui/graphics/resources.d index 6099b40a..6ce5605c 100644 --- a/src/dlangui/graphics/resources.d +++ b/src/dlangui/graphics/resources.d @@ -351,6 +351,8 @@ class StateDrawable : Drawable { foreach(item; element.elements) { if (item.tag.name.equal("item")) { string drawableId = attrValue(item, "drawable", "android:drawable"); + if (drawableId.startsWith("@drawable/")) + drawableId = drawableId[10 .. $]; ColorTransform transform; transform.addBefore = colorTransformFromStringAdd(attrValue(item, "color_transform_add1", "android:transform_color_add1")); transform.multiply = colorTransformFromStringMult(attrValue(item, "color_transform_mul", "android:transform_color_mul")); @@ -394,8 +396,12 @@ class StateDrawable : Drawable { override void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0) { foreach(ref item; _stateList) if (item.matchState(state)) { - if (!item.drawable.isNull) + if (!item.drawable.isNull) { + if (state & State.Checked) { + Log.d("Found item for checked state: ", item.stateMask, " ", item.stateValue); + } item.drawable.drawTo(buf, rc, state, tilex0, tiley0); + } return; } } @@ -620,24 +626,28 @@ class DrawableCache { return _drawable; if (_filename !is null) { // reload from file - if (_filename.endsWith(".xml")) { + if (_filename.endsWith(".xml") || _filename.endsWith(".XML")) { // XML drawables support StateDrawable d = new StateDrawable(); if (!d.load(_filename)) { + Log.e("failed to load .xml drawable from ", _filename); destroy(d); _error = true; } else { + Log.d("loaded .xml drawable from ", _filename); _drawable = d; } } else { // PNG/JPEG drawables support DrawBufRef image = imageCache.get(_filename, transform); if (!image.isNull) { - bool ninePatch = _filename.endsWith(".9.png"); + bool ninePatch = _filename.endsWith(".9.png") || _filename.endsWith(".9.PNG"); _transformed[transform] = new ImageDrawable(image, _tiled, ninePatch); return _transformed[transform]; - } else + } else { + Log.e("failed to load image from ", _filename); _error = true; + } } } return _drawable; @@ -743,6 +753,8 @@ class DrawableCache { if (fn !is null) { _idToFileMap[id] = fn; return fn; + } else { + Log.w("resource ", id, " is not found"); } } return null; diff --git a/src/dlangui/platforms/windows/win32fonts.d b/src/dlangui/platforms/windows/win32fonts.d index 1b2f5a07..3a7400eb 100644 --- a/src/dlangui/platforms/windows/win32fonts.d +++ b/src/dlangui/platforms/windows/win32fonts.d @@ -286,9 +286,11 @@ class Win32Font : Font { lf.lfFaceName[def.face.length] = 0; lf.lfHeight = -size; lf.lfItalic = italic; - lf.lfOutPrecision = OUT_TT_ONLY_PRECIS; + lf.lfOutPrecision = OUT_OUTLINE_PRECIS; //OUT_TT_ONLY_PRECIS; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf.lfQuality = ANTIALIASED_QUALITY; + //lf.lfQuality = NONANTIALIASED_QUALITY; //ANTIALIASED_QUALITY; + //lf.lfQuality = PROOF_QUALITY; //ANTIALIASED_QUALITY; + lf.lfQuality = size < 18 ? NONANTIALIASED_QUALITY : PROOF_QUALITY; //ANTIALIASED_QUALITY; lf.lfPitchAndFamily = def.pitchAndFamily; _hfont = CreateFontIndirectA(&lf); _drawbuf = new Win32ColorDrawBuf(1, 1); diff --git a/src/dlangui/widgets/controls.d b/src/dlangui/widgets/controls.d index 9405faf1..e0b97828 100644 --- a/src/dlangui/widgets/controls.d +++ b/src/dlangui/widgets/controls.d @@ -30,14 +30,33 @@ Authors: $(WEB coolreader.org, Vadim Lopatin) module dlangui.widgets.controls; import dlangui.widgets.widget; +import dlangui.widgets.layouts; +/// vertical spacer to fill empty space in vertical layouts +class VSpacer : Widget { + this() { + styleId = "VSpacer"; + } +} +/// horizontal spacer to fill empty space in horizontal layouts +class HSpacer : Widget { + this() { + styleId = "HSpacer"; + } +} /// static text widget class TextWidget : Widget { - this(string ID = null) { + this(string ID = null, string textResourceId = null) { super(ID); styleId = "TEXT"; + _text = textResourceId; + } + this(string ID, dstring rawText) { + super(ID); + styleId = "TEXT"; + _text = rawText; } protected UIString _text; /// get widget text @@ -49,7 +68,7 @@ class TextWidget : Widget { return this; } /// set text to show - @property Widget text(ref UIString s) { + override @property Widget text(ref UIString s) { _text = s; requestLayout(); return this; @@ -152,7 +171,11 @@ class ImageWidget : Widget { sz.x = img.width; sz.y = img.height; applyAlign(rc, sz); - img.drawTo(buf, rc, state); + uint st = state; + if (state & State.Checked) { + Log.d("Drawing image for checked state"); + } + img.drawTo(buf, rc, st); } } } @@ -160,18 +183,98 @@ class ImageWidget : Widget { /// button with image only class ImageButton : ImageWidget { this(string ID = null, string drawableId = null) { - super(ID); + super(ID, drawableId); styleId = "BUTTON"; _drawableId = drawableId; + clickable = true; focusable = true; trackHover = true; } } +/// button with image and text +class ImageTextButton : HorizontalLayout { + protected ImageWidget _icon; + protected TextWidget _label; + override @property dstring text() { return _label.text; } + override @property Widget text(dstring s) { _label.text = s; requestLayout(); return this; } + override @property Widget text(ref UIString s) { _label.text = s; requestLayout(); return this; } + this(string ID = null, string drawableId = null, string textResourceId = null) { + super(ID); + styleId = "BUTTON"; + _icon = new ImageWidget("icon", drawableId); + _label = new TextWidget("label", textResourceId); + _label.styleId = "BUTTON_LABEL"; + _icon.state = State.Parent; + _label.state = State.Parent; + addChild(_icon); + addChild(_label); + clickable = true; + focusable = true; + trackHover = true; + } + 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; + } +} + +/// checkbox +class CheckBox : ImageTextButton { + this(string ID = null, string textResourceId = null) { + super(ID, "btn_check", textResourceId); + styleId = "TRANSPARENT_BUTTON_BACKGROUND"; + checkable = true; + } + this(string ID, dstring labelText) { + super(ID, "btn_check", labelText); + styleId = "TRANSPARENT_BUTTON_BACKGROUND"; + checkable = true; + } + // called to process click and notify listeners + override protected bool handleClick() { + checked = !checked; + return super.handleClick(); + } +} + +/// radio button +class RadioButton : ImageTextButton { + this(string ID = null, string textResourceId = null) { + super(ID, "btn_radio", textResourceId); + styleId = "TRANSPARENT_BUTTON_BACKGROUND"; + checkable = true; + } + this(string ID, dstring labelText) { + super(ID, "btn_radio", labelText); + styleId = "TRANSPARENT_BUTTON_BACKGROUND"; + checkable = true; + } + // called to process click and notify listeners + override protected bool handleClick() { + checked = true; + return super.handleClick(); + } + +} + +/// Text only button class Button : Widget { protected UIString _text; override @property dstring text() { return _text; } override @property Widget text(dstring s) { _text = s; requestLayout(); return this; } + override @property Widget text(ref UIString s) { _text = s; requestLayout(); return this; } @property Widget textResource(string s) { _text = s; requestLayout(); return this; } this(string ID = null) { super(ID); diff --git a/src/dlangui/widgets/styles.d b/src/dlangui/widgets/styles.d index 6cceabe3..18d8dfdc 100644 --- a/src/dlangui/widgets/styles.d +++ b/src/dlangui/widgets/styles.d @@ -523,10 +523,11 @@ class Theme : Style { _backgroundColor = 0xFFFFFFFF; // transparent _textColor = 0x000000; // black _align = Align.TopLeft; - _fontSize = 24; // TODO: from settings or screen properties / DPI + _fontSize = 14; // TODO: from settings or screen properties / DPI _fontStyle = FONT_STYLE_NORMAL; _fontWeight = 400; - _fontFace = "Arial"; // TODO: from settings + //_fontFace = "Arial"; // TODO: from settings + _fontFace = "Verdana"; // TODO: from settings _fontFamily = FontFamily.SansSerif; _minHeight = 0; _minWidth = 0; @@ -635,10 +636,18 @@ Theme createDefaultTheme() { Log.d("Creating default theme"); Theme res = new Theme("default"); //res.fontSize(14); - res.fontSize(24); + version (Windows) { + res.fontFace = "Verdana"; + } + //res.fontFace = "Arial Narrow"; + res.fontSize = 13; // TODO: choose based on DPI Style button = res.createSubstyle("BUTTON").backgroundImageId("btn_default_small").alignment(Align.Center); - Style buttonTransparent = res.createSubstyle("BUTTON_TRANSPARENT").backgroundImageId("btn_default_small_transparent").alignment(Align.Center); - Style text = res.createSubstyle("TEXT").margins(Rect(2,2,2,2)).padding(Rect(1,1,1,1)); + res.createSubstyle("BUTTON_TRANSPARENT").backgroundImageId("btn_default_small_transparent").alignment(Align.Center); + res.createSubstyle("BUTTON_LABEL").layoutWidth(FILL_PARENT).alignment(Align.Left|Align.VCenter); + res.createSubstyle("BUTTON_ICON").alignment(Align.Center); + res.createSubstyle("TEXT").margins(Rect(2,2,2,2)).padding(Rect(1,1,1,1)); + res.createSubstyle("HSPACER").layoutWidth(FILL_PARENT).layoutWeight(100); + res.createSubstyle("VSPACER").layoutHeight(FILL_PARENT).layoutWeight(100); //button.createState(State.Enabled | State.Focused, State.Focused).backgroundImageId("btn_default_small_normal_disable_focused"); //button.createState(State.Enabled, 0).backgroundImageId("btn_default_small_normal_disable"); //button.createState(State.Pressed, State.Pressed).backgroundImageId("btn_default_small_pressed"); @@ -692,6 +701,12 @@ Theme createDefaultTheme() { menuItem.createState(State.Selected, State.Selected).backgroundColor(0x00F8F9Fa); menuItem.createState(State.Hovered, State.Hovered).backgroundColor(0xC0FFFF00); + Style transparentButtonBackground = res.createSubstyle("TRANSPARENT_BUTTON_BACKGROUND").padding(Rect(4,2,4,2)); //.backgroundColor(0xE0E080) ; + transparentButtonBackground.createState(State.Focused, State.Focused).backgroundColor(0x40C0C000); + transparentButtonBackground.createState(State.Pressed, State.Pressed).backgroundColor(0x4080C000); + transparentButtonBackground.createState(State.Selected, State.Selected).backgroundColor(0x00F8F9Fa); + transparentButtonBackground.createState(State.Hovered, State.Hovered).backgroundColor(0xC0FFFF00); + Style poopupMenu = res.createSubstyle("POPUP_MENU").backgroundImageId("popup_menu_background_normal"); Style listItem = res.createSubstyle("LIST_ITEM"); diff --git a/src/dlangui/widgets/widget.d b/src/dlangui/widgets/widget.d index f246258d..a3f199b5 100644 --- a/src/dlangui/widgets/widget.d +++ b/src/dlangui/widgets/widget.d @@ -259,6 +259,8 @@ class Widget { @property dstring text() { return ""; } /// sets widget content text (override to support this) @property Widget text(dstring s) { return this; } + /// sets widget content text (override to support this) + @property Widget text(ref UIString s) { return this; } //================================================================== // Layout and drawing related methods @@ -337,12 +339,39 @@ class Widget { return _pos.isPointInside(x, y); } + protected bool _clickable; + @property bool clickable() { return _clickable; } + @property Widget clickable(bool flg) { _clickable = flg; return this; } + + protected bool _checkable; + @property bool checkable() { return _checkable; } + @property Widget checkable(bool flg) { _checkable = flg; return this; } + + protected bool _checked; + /// get checked state + @property bool checked() { return (state & State.Checked) != 0; } + /// set checked state + @property Widget checked(bool flg) { + if (flg != checked) { + if (flg) + setState(State.Checked); + else + resetState(State.Checked); + invalidate(); + } + return this; + } + protected bool _focusable; @property bool focusable() { return _focusable; } @property Widget focusable(bool flg) { _focusable = flg; return this; } + @property bool focused() { return (window !is null && window.focusedWidget is this && (state & State.Focused)); } + + + /// returns true if this widget and all its parents are visible @property bool visible() { if (visibility != Visibility.Visible) @@ -390,9 +419,15 @@ class Widget { // ======================================================= // Events + // called to process click and notify listeners + protected bool handleClick() { + bool res = onClickListener(this); + return res; + } + /// process key event, return true if event is processed. bool onKeyEvent(KeyEvent event) { - if (onClickListener.assigned) { + if (clickable) { // support onClick event initiated by Space or Return keys if (event.action == KeyAction.KeyDown) { if (event.keyCode == KeyCode.SPACE || event.keyCode == KeyCode.RETURN) { @@ -403,7 +438,7 @@ class Widget { if (event.action == KeyAction.KeyUp) { if (event.keyCode == KeyCode.SPACE || event.keyCode == KeyCode.RETURN) { resetState(State.Pressed); - onClickListener(this); + handleClick(); return true; } } @@ -415,7 +450,7 @@ class Widget { bool onMouseEvent(MouseEvent event) { //Log.d("onMouseEvent ", id, " ", event.action, " (", event.x, ",", event.y, ")"); // support onClick - if (onClickListener.assigned) { + if (clickable) { if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) { setState(State.Pressed); if (focusable) @@ -424,7 +459,7 @@ class Widget { } if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) { resetState(State.Pressed); - onClickListener(this); + handleClick(); return true; } if (event.action == MouseAction.FocusOut || event.action == MouseAction.Cancel) {