From cd731525afbe139cb957be254f594e6e30952e2f Mon Sep 17 00:00:00 2001 From: Vadim Lopatin <buggins@fromru.com> Date: Thu, 17 Apr 2014 22:48:13 +0400 Subject: [PATCH] fix buttons behavior --- examples/example1/src/main.d | 9 +-- res/btn_default_small.xml | 58 ++++++++++-------- res/mdpi/btn_default_small_normal.9.png | Bin 0 -> 1508 bytes .../btn_default_small_normal_disable.9.png | Bin 0 -> 1487 bytes ...default_small_normal_disable_focused.9.png | Bin 0 -> 1506 bytes res/mdpi/btn_default_small_pressed.9.png | Bin 0 -> 1413 bytes res/mdpi/btn_default_small_selected.9.png | Bin 0 -> 1391 bytes src/dlangui/widgets/controls.d | 19 ++++++ src/dlangui/widgets/lists.d | 2 +- src/dlangui/widgets/menu.d | 1 + src/dlangui/widgets/tabs.d | 2 + src/dlangui/widgets/widget.d | 51 ++++++++++++--- 12 files changed, 101 insertions(+), 41 deletions(-) create mode 100644 res/mdpi/btn_default_small_normal.9.png create mode 100644 res/mdpi/btn_default_small_normal_disable.9.png create mode 100644 res/mdpi/btn_default_small_normal_disable_focused.9.png create mode 100644 res/mdpi/btn_default_small_pressed.9.png create mode 100644 res/mdpi/btn_default_small_selected.9.png diff --git a/examples/example1/src/main.d b/examples/example1/src/main.d index 39512412..ba43def4 100644 --- a/examples/example1/src/main.d +++ b/examples/example1/src/main.d @@ -1,4 +1,4 @@ -module winmain; +module main; import dlangui.all; import std.stdio; @@ -24,13 +24,6 @@ extern (C) int UIAppMain(string[] args) { // select translation file - for english language i18n.load("en.ini"); //"ru.ini", "en.ini" - - DrawBufRef img = imageCache.get("C:\\projects\\d\\dlangui\\res\\mdpi\\btn_radio_on_holo_light.png"); - ColorDrawBuf buf = cast(ColorDrawBuf)img.get; - //GrayDrawBuf gbuf = cast(GrayDrawBuf)img.get; - uint * row = buf.scanLine(0); - Log.d("btn_radio_on_holo_light pixels: ", row[0], row[1], row[2]); - // create window Window window = Platform.instance.createWindow("My Window", null); diff --git a/res/btn_default_small.xml b/res/btn_default_small.xml index 358969f7..5485ea03 100644 --- a/res/btn_default_small.xml +++ b/res/btn_default_small.xml @@ -1,25 +1,33 @@ -<?xml version="1.0" encoding="utf-8"?> -<selector xmlns:android="http://schemas.android.com/apk/res/android" - android:constantSize="true" - android:dither="false" - android:variablePadding="false" > - <item - android:drawable="btn_default_small_normal_disable_focused" - android:state_enabled="false" /> - android:state_focused="true" /> - <item - android:drawable="btn_default_small_normal_disable" - android:state_focused="true" /> - <item - android:drawable="btn_default_small_pressed" - android:state_pressed="true" /> - <item - android:drawable="btn_default_small_selected" - android:state_selected="true" /> - <item - android:drawable="btn_default_small_normal_hover" - android:state_hovered="true" /> - <item - android:drawable="btn_default_small_normal" - /> -</selector> +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2008 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_window_focused="false" android:state_enabled="true" + android:drawable="@drawable/btn_default_small_normal" /> + <item android:state_window_focused="false" android:state_enabled="false" + android:drawable="@drawable/btn_default_small_normal_disable" /> + <item android:state_pressed="true" + android:drawable="@drawable/btn_default_small_pressed" /> + <item android:state_focused="true" android:state_enabled="true" + android:drawable="@drawable/btn_default_small_selected" /> + <item android:state_enabled="true" + android:drawable="@drawable/btn_default_small_normal" /> + <item android:state_focused="true" + android:drawable="@drawable/btn_default_small_normal_disable_focused" /> + <item + android:drawable="@drawable/btn_default_small_normal_disable" /> +</selector> + diff --git a/res/mdpi/btn_default_small_normal.9.png b/res/mdpi/btn_default_small_normal.9.png new file mode 100644 index 0000000000000000000000000000000000000000..5dddd4640d9c603443dc3fc2ac3dc01e82a92c91 GIT binary patch literal 1508 zcmeAS@N?(olHy`uVBq!ia0vp^VnD3M!3HD`oXegDq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1FfgZOhD4M^`1)8S=jZArg4F0$<Q4#RGcefLR}>^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Keo`G(%fti7VnW3Jc zv5C34xsHO7fuVuEfswwUk*=Y+m9dePfq?=PC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DR zmzV368|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQivaF)=B> zw8T~k=u(ImatnNY;RfdwLjwvJWcn3}1^R}12Ku?VAb){X7ncO3BAkI$b#X{#L8^XG zYH@yPQ8F+-(v)GEfnkT=B9KC$Ypnc>GJ%njnB$V4T$-DjSK{ens|1wMOUX>JGIVls zHa9e}FflYTFtac;bTYHFbT)K#a&vYxbv83JgqeX&ucd{#rK6*%nUjm5xuKzpn}w5w znT5Hble3eVo1vkh2~4kNUU5lcUUDkT-b|pqK)r?*ZcYYx^;$U>r6!i-7lq{K=fF}x zKt_H^esM;Afr4|ese*4}a%LWg4~ia$Z(UN0GRsm^+=}vZ6~N(Zm5IfEXG0@%b2D>e zBNHQI?EZ%6O(7@D^ns4i2PF=q!~zonra%xAp7ennc;-pX1Ll|_VAl9psb<W;z$D`7 z;uunKYfD(H-(druyhCn{o*cdGGb|3X$TZ$<6)xcOJCOK-mmyR9#$kzBEiDxZIe!o9 z8GZ^<_dPE5^75{0KOfa>OkRD$_LN4B#`Dvgbd*_{<#sm&AK-Lg7ZPvaKVYrEx=v`N z)ftA)bCXndO7pdEuh(uCWD-|be=*%au3z45@kQG`b*xXe9XGUzJNNvvyB@Q;TF`8X zvuw==dH?J?@PFxBL%Z)?i!?H=UCx}$3ECEMzCfq5=a^iA{rS)Fv0LIMJA4vx{AO{z zAS7)?_Q^e$%mTYNmfev3y?Ae|Uh5OX;v?Q`c5HMxb@HK&#l|d^ZJrs7|N1<dJCBNp z9P;_GZri$zGauXA+)?u9n}1Bj^TNZQDIZjh=Plvj+y3fQlWx#6&%lF;``RmY?g~ya zSvYg~KgHJj$@3UuxWaXIn_OGh^~ig|1R>Qd9T}guAKuJmJ-$)JQM!Mtww9EK+3x<O zH%eXGyt&>^Ui5NVc5y}5yT~<_Wt(<HH7N8(-#h51moKyXOR0`T*sPjaZD9hcqL+0} zXMJy3qF?G|*8jF}%CgKYQER8@x4m_eK3;fs*<qdy$7=l4CTH%yzdu2?Z@S3hbhFvM zh3j70Waqw7w25O}$N0RV`9RNawmppV7|tKqy5dRVkr%d;<eB??)~}KBxcFD(L#j<2 zLwK5Sws2kS<vUw5_Y`kt*tY7Z)JHS-rL|iY3od%-_PL%#f??hkuO(YnSEPf=T~Aj( Jmvv4FO#obYCF}qI literal 0 HcmV?d00001 diff --git a/res/mdpi/btn_default_small_normal_disable.9.png b/res/mdpi/btn_default_small_normal_disable.9.png new file mode 100644 index 0000000000000000000000000000000000000000..6ab5c4a20e03d8c0381da37d2213c0a69f6b7c5e GIT binary patch literal 1487 zcmbVMZA=qq96zK1LQuiMm<+qynJf@#@18<?ZJ|T1FVeB{Qiu{!@n{cvz}?mBA*Goc z(I8o~D1I2?kZr);*rM?znuV#bxe3?+0*iAD2pfz^Cg7Z#F4MRxP__@m54+^<dH&Dy z|NZ{&_hxSPwzc7L;SdC^HD?;E;`*%kz7!TBe!B-M8pUO!U@R2!xl*B;<S8h_&XrKG znIX$4D@EFC_VrO|5ENWW7ZeJGmRGelj**jo9l4uvif9N*OLsd-TLmS+B~%&B>X3ym zx)7MQ>yRBv3ubZZDF>bD;i-I2c7e@PVbj==^q1i@w^k%zD1n6COeO2mx^>7RuU6dq zk5L3(R1qq4$dXfqmRwlR@f56-V=^12!eAAUgX9z($CF?M1~3#;pg<u5xHeg##V~mJ zK}2i3y;N&8n3ipck`8eQf>Vp4)z#JV>SQ^`m!UwT(fBzO3Yn-ObJef{>6Wps%>f1j z<+Aa#Q=mB(_A`<tT$P|hL{FDOV4N1q3Nh<iPL!B3)J-~3AjeRK@yE5O?GmiizizCm z?JB5oQmB=3aaFuctVikQ09ef3(+&9*MQ^k@JS`T5tTb@8Du!YOvq6W5H*z~|*8+mj z;~+(y0u-1^4FI9iX!O8HnDiM+y$XN;$7)!OTCG&+lQF^oZ~zP@HKA6iaX{z^l?ecl z62O{Smq4;MDqxou?Ji*zrl(@HdY&Q$jxXT2%0LI?IyixIIXEY*&sV}0(nhm>*<YTe zXbluk@2Bi0o@3y}{A%e{?CXI7$5nW;B1MtBdfZD``~S%qDmsJuo8v#t5;zh&(7#=2 zeNk8$9*Pwwh8IV}TC92mK|xQ<hKvID=-1m**{fK@+tF7Oh7)@mwg_RK`a3%I!B}hW z4P|~qtIhk>*;C$i8*iLT7z*-+M^+wqXwX@Q&zs~Ex4ki`m%GTqiro*>>UL&@91OO6 zk{<N&w)p(<9kq?X_xSZEo#Slr`!&BR+EI1Jk*%|TPsFdQ9~@^NL|sFrp$pRb0pr8n z?+yNfSLW0%$PrAoW~#Y=MkgGo+mGLSF1Dld^r1d!NQ>+6oI~=;1afz;Z+5D?_NUQ{ zN=f+PX-(*~^lChtlRw#W{#1FeYG(pf^v$8M=6J`htnT*OyH}c~Bxmw!BF2ISC7({Z zr_VO`P1(z=dHZ&?5ix0_aiQLhNcGLUV?UJN`J>B9mP}f=XG&9N<77r1cz6At>j@X2 z{?^ytXz~u9L}JE@5*vu(zczTk{BUw;sAtpcQ6W4bHa8|_*zCLC-%k8K^P{q1(0fZ= zmE%Y_0gVKk*VBpPh0^0Wd**MKk60u(r=9besr|lVS@>_Gm*{6w%`ZmEJKoBjx!59E z@LYc9BRVNHuWdsc{9RQ`fB2ctrAK>w<rh4q_ssX3qDN+h&RW^=D~&&INji6}Goq?B z+SvU)9!5mh&A~o|xwMtpMK45UKF%%rws(_bI;e^9m0VXp8i<;Z#@_v)VD9AeSw$i9 k{V&9Pc56oeXV;ntD94j_Vj<mF?*GM_joF6N#NLDd0HO;a=Kufz literal 0 HcmV?d00001 diff --git a/res/mdpi/btn_default_small_normal_disable_focused.9.png b/res/mdpi/btn_default_small_normal_disable_focused.9.png new file mode 100644 index 0000000000000000000000000000000000000000..c65bace36acdbcc35db309ccf74eed118979d273 GIT binary patch literal 1506 zcmeAS@N?(olHy`uVBq!ia0vp^VnD3M!3HD`oXegDq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1FfgZOhD4M^`1)8S=jZArg4F0$<Q4#RGcefLR}>^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Keo`G(%fti7VnW3Jc zv5C34xsHO7fuVuEfswwUk*=Y+m9dePfq?=PC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DR zmzV368|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQivaF)=B> zw8T~k=u(ImatnNY;RfdwLjwvJWcn3}1^R}12Ku?VAb){X7ncO3BAkI$b#X{#L8^XG zYH@yPQ8F+-(v)GEfnkT=B9KC$Ypnc>GJ%njnB$V4T$-DjSK{ens|1wMOUX>JGIVls zHa9e}FflYTFtac;bTYHFbT)K#a&vYxbv83JgqeX&ucd{BshP8}g_Db+xuKzpn}w5w znT5Hble3eVo1vkh2~4kNUU5lcUUDkT-b|pqP`&1O^;$U>r6!i-7lq{K=fF}xKt_H^ zesM;Afr4|ese*4}a%LWg4~ia$Z(UN0GRsm^+=}vZ6~N(Zm5IfEXG0@%b2D>eBNHQI z?EZ%6O(7@D^ns4i2PF=q!~zonra%xAp7ennc;-pX1Ll|_VAlBN#TdfCz$E19;uunK z>rS|}H?yO_JzM?2jtoVyrm#h=98F?fVgDKv^l$viIC4l{p{c3&#*d7n@&Zk3Q&n!T zHnsNq>4*qkbm%F!es}L~oY}p!P30GlH7ai2dGr0gzhz}J7qggWe4Mk0pW)BXDM7D) zCZuRy_M9FpThb<RV><WIQ|fcRtiM06NJi|zmByb9VSR4JnX}V8nO0j)IKSqePJxcV zfoU}d9K|O$aS0c*w#nQ!df**Dv2bg?)_0?wlfO@E*|A~XqcpRxHCq=X%;~g9IrI5h z${&-BbHzW+_;LG7TwF6Flf;wT^_O#Uds%b-i5CPcVmt6wfMtrIgmK@d)@KK_0%Ceg zca|RG>2XxLWyJI2cyy^w$$~h!BNLn$Ui>p&tKiBtZI6~o@x`-~*BEYNn|)kL&A=`! z-)M{1BZItB!<CjBC1%SB=%1fbc*pAB*Hs*hfya34FWq2cs{0h7!zp#F!6<KEWyI8q zoijvsb-QGyeBez<h!b75^^baJ<Jqk)?jmuujolkx?-DGRahG0QoGN&;bmoFH;&$)0 zdY3<UUeElQ-+s58>9oi9j&~mn5OO*ts43Cx#QwFB-FtWRoyXctO9Z?Wo4;#Wv)%V_ zVs8{&=k~Vuz4<P+U6)JFZabm#-B5TMpYruP`u14`7JK4#JLPUp_F-J+sGP^Te;KbV z%eg<NKL1X>m8ZS*ua7|Q_xO@oM-p~++UM<Km0*zB{YHB742j#IQrFYf&t;ucLK6V= C_aXKG literal 0 HcmV?d00001 diff --git a/res/mdpi/btn_default_small_pressed.9.png b/res/mdpi/btn_default_small_pressed.9.png new file mode 100644 index 0000000000000000000000000000000000000000..43e82f977878dff5b8501a8916d69fc8fa89d639 GIT binary patch literal 1413 zcmeAS@N?(olHy`uVBq!ia0vp^VnD3M!3HD`oXegDq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1FfgZOhD4M^`1)8S=jZArg4F0$<Q4#RGcefLR}>^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Keo`G(%fti7VnW3Jc zv5C34xsHO7fuVuEfswwUk*=Y+m9dePfq?=PC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DR zmzV368|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQivaF)=B> zw8T~k=u(ImatnNY;RfdwLjwvJWcn3}1^R}12Ku?VAb){X7ncO3BAkI$b#X{#L8^XG zYH@yPQ8F+-(v)GEfnkT=B9KC$Ypnc>GJ%njnB$V4T$-DjSK{ens|1wMOUX>JGIVls zHa9e}FflYTFtac;bTYHFbT)K#a&vYxbv83JgqeX&ucd{#rK6*%tCNeNxuKzpn}w5w znT5Hble3eVo1vkh2~4kNUU5lcUUDkT-b|pqP`xgA^;$U>r6!i-7lq{K=fF}xKt_H^ zesM;Afr4|ese*4}a%LWg4~ia$Z(UN0GRsm^+=}vZ6~N(Zm5IfEXG0@%b2D>eBNHQI z?EZ%6O(7@D^ns4i2PF=q!~zonra%xAp7ennc;-pX1Ll|_VAjYMi95%@z_``Z#WAGf z)|D_{Z)QV*xt`^&t}OgbB6~PQTWme|de%>3ukT>5pH#8>xRY(Apcnrlg`=x-jr}%7 zzOCCb*JXOr14ps6xO@A2)EFo5f9hb}BI(j#Q?cu$MUsq>lvAJN<B1;+RGepVDQ4^{ zytCJ8XP!E{tbA$t-iK#zrv7hQZo568@5Y(vw<-IboAnyzornnKdHZBa>zC+1rTaT7 zx+NJi-}p?juxFh-`B_w7ztYB!Cfgjnn(uG;`0>uZfRK(1hC+c!^7@$?dE2x?Ie)JD zt9EXt_|((>r~jUf-Z&*<>FVT;q^&W979XudlV!UU9Sl80vd_jI>6h4gB6*d@`_Qm} zrAf1*d2{(cezkaOt$K7ua8CW{;Ei!_3wvj~Gj^#yb=#(uwb|*fvUZN|qx)A1Jq<ha z>!!P0E#>)9tPoS)Z7b@p($(DmWz{<|2c9kaR&59q_;-tI&5otbYa>?N_;dd914;L@ zdmr}kzkT4^>yuZ;(!F}d_Uk*HCvQ}I^4H`}Pjq|X#2dC;iPJZ}?UH1bo1s*fyvOR2 z=9F1AU2h7P+gM#Vqq{(RzU$Mo-)dx@`4`$cKS~VvH=Ti*A-8+6=F5ChW>CTC>FVdQ I&MBb@0Bgbd7XSbN literal 0 HcmV?d00001 diff --git a/res/mdpi/btn_default_small_selected.9.png b/res/mdpi/btn_default_small_selected.9.png new file mode 100644 index 0000000000000000000000000000000000000000..7a376a97f0d695fb8dedaf5f7dc8708276f8a174 GIT binary patch literal 1391 zcmeAS@N?(olHy`uVBq!ia0vp^VnD3M!3HD`oXegDq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1FfgZOhD4M^`1)8S=jZArg4F0$<Q4#RGcefLR}>^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Keo`G(%fti7VnW3Jc zv5C34xsHO7fuVuEfswwUk*=Y+m9dePfq?=PC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DR zmzV368|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQivaF)=B> zw8T~k=u(ImatnNY;RfdwLjwvJWcn3}1^R}12Ku?VAb){X7ncO3BAkI$b#X{#L8^XG zYH@yPQ8F+-(v)GEfnkT=B9KC$Ypnc>GJ%njnB$V4T$-DjSK{ens|1wMOUX>JGIVls zHa9e}FflYTFtac;bTYHFbT)K#a&vYxbv83JgqeX&ucd{Bft#VRsgsMLxuKzpn}w5w znT5Hble3eVo1vkh2~4kNUU5lcUUDkT-b|pqP`xI2^;$U>r6!i-7lq{K=fF}xKt_H^ zesM;Afr4|ese*4}a%LWg4~ia$Z(UN0GRsm^+=}vZ6~N(Zm5IfEXG0@%b2D>eBNHQI z?EZ%6O(7@D^ns4i2PF=q!~zonra%xAp7ennc;-pX1Ll|_VAkmW$CAy!z&PL2#WAGf z)}1hGKW0M#*=lnRjUOc(6WJKK+&f&HXFm=oVmKAk7=7WALLsAygNI4yihw2!j>a|Z z>FXVTpKQwA<e0QX-7@O@=iBC+g@t#rSHDqBG@9Y5upx$JTcetQWs!;l{|@%JgGXm+ zoy(bU;NH)R*F3B1*FIkS?$fWAZ#LYvKlbUA+!W<&ukV&+Z#CYxSJ_W!dw8Ex*7h=m zCG}nN%|nlPyKpTLE`NMB&NXx0LkaQDt;>0Xl^y3LzPfedO6%i8eHwR<C?46FbUJAI z2Br5N#Yes$xtFzH<atMTn1_jJ<?NiIPfE)p1Q*Qs>8`ybSN43se}_Vw*o`Y33wMaB z9*yigv}YQ}rbSndC&|^ur0+hP7B<B$^RM~Qd0`u7iym}-(Z6Oz{;sn{a?8WJZi%vg z|M(~Es7U|O^|tG>FLZMqEmFIz`}@mA^MJ$8*w+8P@Quyp%FZb(Yrcupez)3igGEfH z@_qyR11IL<<R!Pmr|7qCVbZz1dq%;ETh<?#Y?ze={JV}^di1$S-ImAi4I|f)RUR>> ne0!aRy;o_**zlbCFOb0CD713zv9QicP!Z_q>gTe~DWM4fzpL@p literal 0 HcmV?d00001 diff --git a/src/dlangui/widgets/controls.d b/src/dlangui/widgets/controls.d index e0b97828..51bbee49 100644 --- a/src/dlangui/widgets/controls.d +++ b/src/dlangui/widgets/controls.d @@ -261,9 +261,26 @@ class RadioButton : ImageTextButton { styleId = "TRANSPARENT_BUTTON_BACKGROUND"; checkable = true; } + + void uncheckSiblings() { + Widget p = parent; + if (!p) + return; + for (int i = 0; i < p.childCount; i++) { + Widget child = p.child(i); + if (child is this) + continue; + RadioButton rb = cast(RadioButton)child; + if (rb) + rb.checked = false; + } + } + // called to process click and notify listeners override protected bool handleClick() { + uncheckSiblings(); checked = true; + return super.handleClick(); } @@ -279,6 +296,7 @@ class Button : Widget { this(string ID = null) { super(ID); styleId = "BUTTON"; + clickable = true; focusable = true; trackHover = true; } @@ -399,6 +417,7 @@ class ScrollBar : AbstractSlider, OnClickHandler { super(ID); styleId = "PAGE_SCROLL"; trackHover = true; + clickable = true; } } diff --git a/src/dlangui/widgets/lists.d b/src/dlangui/widgets/lists.d index ce8be428..66cf932e 100644 --- a/src/dlangui/widgets/lists.d +++ b/src/dlangui/widgets/lists.d @@ -236,7 +236,7 @@ class ListWidget : WidgetGroup, OnScrollHandler { } /// override to handle focus changes - override protected void onFocusChange(bool focused) { + override protected void handleFocusChange(bool focused) { updateSelectedItemFocus(); } diff --git a/src/dlangui/widgets/menu.d b/src/dlangui/widgets/menu.d index abfd671c..99431e57 100644 --- a/src/dlangui/widgets/menu.d +++ b/src/dlangui/widgets/menu.d @@ -90,6 +90,7 @@ class MenuItemWidget : HorizontalLayout { _label.text = _item.label; addChild(_label); trackHover = true; + clickable = true; } } diff --git a/src/dlangui/widgets/tabs.d b/src/dlangui/widgets/tabs.d index f5509454..79c6e2e3 100644 --- a/src/dlangui/widgets/tabs.d +++ b/src/dlangui/widgets/tabs.d @@ -20,6 +20,7 @@ Authors: $(WEB coolreader.org, Vadim Lopatin) */ module dlangui.widgets.tabs; +import dlangui.core.signals; import dlangui.widgets.layouts; import dlangui.widgets.controls; @@ -82,6 +83,7 @@ class TabItemWidget : HorizontalLayout { addChild(_label); addChild(_closeButton); setItem(item); + clickable = true; trackHover = true; } protected bool onClick(Widget source) { diff --git a/src/dlangui/widgets/widget.d b/src/dlangui/widgets/widget.d index c0635dfc..7b297b41 100644 --- a/src/dlangui/widgets/widget.d +++ b/src/dlangui/widgets/widget.d @@ -52,10 +52,21 @@ enum Orientation : ubyte { Horizontal } +/// interface - slot for onClick interface OnClickHandler { bool onClick(Widget source); } +/// interface - slot for onCheckChanged +interface OnCheckHandler { + bool onCheckChanged(Widget source, bool checked); +} + +/// interface - slot for onFocusChanged +interface OnFocusHandler { + bool onFocusChanged(Widget source, bool focused); +} + class Widget { /// widget id protected string _id; @@ -152,10 +163,15 @@ class Widget { @property uint state() const { if ((_state & State.Parent) != 0 && _parent !is null) return _parent.state; - return _state; + return _state | State.WindowFocused; // TODO: } /// override to handle focus changes - protected void onFocusChange(bool focused) { + protected void handleFocusChange(bool focused) { + onFocusChangeListener(this, checked); + } + /// override to handle check changes + protected void handleCheckChange(bool checked) { + onCheckChangeListener(this, checked); } /// set new widget state (set of flags from State enum) @property Widget state(uint newState) { @@ -166,9 +182,14 @@ class Widget { invalidate(); // notify focus changes if ((oldState & State.Focused) && !(newState & State.Focused)) - onFocusChange(false); + handleFocusChange(false); else if (!(oldState & State.Focused) && (newState & State.Focused)) - onFocusChange(true); + handleFocusChange(true); + // notify checked changes + if ((oldState & State.Checked) && !(newState & State.Checked)) + handleCheckChange(false); + else if (!(oldState & State.Checked) && (newState & State.Checked)) + handleCheckChange(true); } return this; } @@ -337,13 +358,23 @@ class Widget { return _pos.isPointInside(x, y); } + /// return true if state has State.Enabled flag set + @property bool enabled() { return (state & State.Enabled) != 0; } + /// change enabled state + @property Widget enabled(bool flg) { flg ? setState(State.Enabled) : resetState(State.Enabled); return this; } + protected bool _clickable; + /// when true, user can click this control, and get onClick listeners called @property bool clickable() { return _clickable; } @property Widget clickable(bool flg) { _clickable = flg; return this; } + @property bool canClick() { return _clickable && enabled && visible; } protected bool _checkable; + /// when true, control supports Checked state @property bool checkable() { return _checkable; } @property Widget checkable(bool flg) { _checkable = flg; return this; } + @property bool canCheck() { return _checkable && enabled && visible; } + protected bool _checked; /// get checked state @@ -425,7 +456,7 @@ class Widget { /// process key event, return true if event is processed. bool onKeyEvent(KeyEvent event) { - if (clickable) { + if (canClick) { // support onClick event initiated by Space or Return keys if (event.action == KeyAction.KeyDown) { if (event.keyCode == KeyCode.SPACE || event.keyCode == KeyCode.RETURN) { @@ -448,7 +479,7 @@ class Widget { bool onMouseEvent(MouseEvent event) { //Log.d("onMouseEvent ", id, " ", event.action, " (", event.x, ",", event.y, ")"); // support onClick - if (clickable) { + if (canClick) { if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) { setState(State.Pressed); if (focusable) @@ -497,10 +528,16 @@ class Widget { return false; } + // ======================================================= + // Signals /// on click event listener (bool delegate(Widget)) Signal!OnClickHandler onClickListener; - + /// checked state change event listener (bool delegate(Widget, bool)) + Signal!OnCheckHandler onCheckChangeListener; + /// focus state change event listener (bool delegate(Widget, bool)) + Signal!OnFocusHandler onFocusChangeListener; + // ======================================================= // Layout and measurement methods