From 3102d485db22177efb7ef96dbdf2c5b539bff2fa Mon Sep 17 00:00:00 2001 From: Ricky Barrette Date: Sat, 11 Feb 2012 12:30:12 -0500 Subject: [PATCH] Added custom number picker for api < 11 compatibility Extracted number picker (non public) from older android source and included it into this project to remain compatible with devices api level < 11. Devices api level > 11 will use native number pickers as the are public facing in the sdk Change-Id: I7cf7cba066b25516e90bd9951f4de7964b7fd613 Signed-off-by: Ricky Barrette --- ExaltedDice/AndroidManifest.xml | 2 +- .../res/drawable/timepicker_down_btn.xml | 30 ++ .../drawable/timepicker_down_disabled.9.png | Bin 0 -> 422 bytes .../timepicker_down_disabled_focused.9.png | Bin 0 -> 580 bytes .../res/drawable/timepicker_down_normal.9.png | Bin 0 -> 795 bytes .../drawable/timepicker_down_pressed.9.png | Bin 0 -> 1161 bytes .../drawable/timepicker_down_selected.9.png | Bin 0 -> 1170 bytes ExaltedDice/res/drawable/timepicker_input.xml | 30 ++ .../drawable/timepicker_input_disabled.9.png | Bin 0 -> 280 bytes .../drawable/timepicker_input_normal.9.png | Bin 0 -> 582 bytes .../drawable/timepicker_input_pressed.9.png | Bin 0 -> 604 bytes .../drawable/timepicker_input_selected.9.png | Bin 0 -> 517 bytes .../res/drawable/timepicker_up_btn.xml | 30 ++ .../res/drawable/timepicker_up_disabled.9.png | Bin 0 -> 491 bytes .../timepicker_up_disabled_focused.9.png | Bin 0 -> 728 bytes .../res/drawable/timepicker_up_normal.9.png | Bin 0 -> 989 bytes .../res/drawable/timepicker_up_pressed.9.png | Bin 0 -> 1433 bytes .../res/drawable/timepicker_up_selected.9.png | Bin 0 -> 1428 bytes ExaltedDice/res/layout-v11/dice_selector.xml | 24 + ExaltedDice/res/layout/dice_selector.xml | 12 +- ExaltedDice/res/layout/main.xml | 2 +- ExaltedDice/res/layout/number_picker.xml | 49 ++ ExaltedDice/res/values/attrs.xml | 27 +- .../android/ExaltedDice/ExaltedDice.java | 292 +++++++---- .../android/ExaltedDice/NumberPicker.java | 488 ++++++++++++++++++ .../ExaltedDice/NumberPickerButton.java | 84 +++ project.properties | 13 + 27 files changed, 958 insertions(+), 125 deletions(-) create mode 100755 ExaltedDice/res/drawable/timepicker_down_btn.xml create mode 100755 ExaltedDice/res/drawable/timepicker_down_disabled.9.png create mode 100755 ExaltedDice/res/drawable/timepicker_down_disabled_focused.9.png create mode 100755 ExaltedDice/res/drawable/timepicker_down_normal.9.png create mode 100755 ExaltedDice/res/drawable/timepicker_down_pressed.9.png create mode 100755 ExaltedDice/res/drawable/timepicker_down_selected.9.png create mode 100755 ExaltedDice/res/drawable/timepicker_input.xml create mode 100755 ExaltedDice/res/drawable/timepicker_input_disabled.9.png create mode 100755 ExaltedDice/res/drawable/timepicker_input_normal.9.png create mode 100755 ExaltedDice/res/drawable/timepicker_input_pressed.9.png create mode 100755 ExaltedDice/res/drawable/timepicker_input_selected.9.png create mode 100755 ExaltedDice/res/drawable/timepicker_up_btn.xml create mode 100755 ExaltedDice/res/drawable/timepicker_up_disabled.9.png create mode 100755 ExaltedDice/res/drawable/timepicker_up_disabled_focused.9.png create mode 100755 ExaltedDice/res/drawable/timepicker_up_normal.9.png create mode 100755 ExaltedDice/res/drawable/timepicker_up_pressed.9.png create mode 100755 ExaltedDice/res/drawable/timepicker_up_selected.9.png create mode 100644 ExaltedDice/res/layout-v11/dice_selector.xml create mode 100755 ExaltedDice/res/layout/number_picker.xml create mode 100755 ExaltedDice/src/com/TwentyCode/android/ExaltedDice/NumberPicker.java create mode 100755 ExaltedDice/src/com/TwentyCode/android/ExaltedDice/NumberPickerButton.java create mode 100644 project.properties diff --git a/ExaltedDice/AndroidManifest.xml b/ExaltedDice/AndroidManifest.xml index b15f1d2..5c0e541 100755 --- a/ExaltedDice/AndroidManifest.xml +++ b/ExaltedDice/AndroidManifest.xml @@ -5,7 +5,7 @@ android:versionCode="15" android:versionName="2.0" > - + diff --git a/ExaltedDice/res/drawable/timepicker_down_btn.xml b/ExaltedDice/res/drawable/timepicker_down_btn.xml new file mode 100755 index 0000000..61a252a --- /dev/null +++ b/ExaltedDice/res/drawable/timepicker_down_btn.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + diff --git a/ExaltedDice/res/drawable/timepicker_down_disabled.9.png b/ExaltedDice/res/drawable/timepicker_down_disabled.9.png new file mode 100755 index 0000000000000000000000000000000000000000..596294b6208043eb7e9261172b8dae6c4e9adb19 GIT binary patch literal 422 zcmV;X0a^ZuP)sKG^^=Od5&NRlKU`sM2Tdq7zRK)WaanSlTT2p|CvKmY+GTLLN= z>;MG}EMWivbTr5Nym(brft2#prbisd_fZtRI5`7t@pjdNCG0AoS$_Ya$HDG_X7AeP z{>2gokh3s=oP}A!00Iag0T4g{0qinwnq~n_Kb^^Z6TqpI@)fdvI+N)pfHzr|z1Ma9 z4BJQ%)V<~cPm3K*PVmU zbWL=f>l!;c`5tuLb~A4_G+^BW)!A=fBHYFR2q1vuuRjqU_4hM)$MPw_0J{ZWlY=wF Q8UO$Q07*qoM6N<$f-gI1)gpAP zzwYW9`+YE|t1SBCn;Bghb0(bqzc})q70I!4z8{@qNHf-2{6gH!|2*cCzOr}=En?(= z?~jlnE(0w9pTF-OjO}iFS!gx8zSThkU(hY0g&eR_1{~2s3dk#Pqgu!TO~6qt00_W7 z1T?V*k}c3c2O7v5e-oPkBwP4o7ZlLIHX6t|XNsZ#uv5TBJWS#Cr*N}62OQPH*NM7Q zF$_aXrBXpV=Lmkd^DVMA$PGE)vjru~Ic>%n9;9u>p84fNM;G9Q6E#tKOa zU?O&6EbXmm`9ZTZf;lYOr)v4wv0+^{OHgO{!eWSR#Fq77NGpzOX0450%bTh_U6+P$ zHjj+lX`1bbLuc(Qkr6Rw#h4KzS literal 0 HcmV?d00001 diff --git a/ExaltedDice/res/drawable/timepicker_down_normal.9.png b/ExaltedDice/res/drawable/timepicker_down_normal.9.png new file mode 100755 index 0000000000000000000000000000000000000000..f17e8f942ac659a47bbfaf81d490eaa8e367d5cd GIT binary patch literal 795 zcmV+$1LXXPP)y zi$@GRQLwFxsD-q2C;b8WSJ@vB{s+>c2y|NuBa_H*6%nB=<|#7Tx%TeszVX~UKO9B9 z=fD9SXNG$}e7|$2hMl}z zE*Syb1c-$a;9BDZ@fx0j#R>(;PZmk>4`65o62KS$l8yh{Hxxj!@J$vfcx2%?EQ}H6 z$7m^Y6JR2dzyV@pIXn!YDL}nUv=+t`Cv_CX+_D^#wehqtWOaXR~n*a@}*tm%U!^Q6`hAnEFQ}S%LHU{A0CR{R)R) zL3ZStg8{q?`2w=mZntlN63i3_dj)jZ66Y2J$uJA3p{1cmVkX z@-gH&Pi$ZyC2P9wg z3}i$o04xje@ckD&G9CZ3oqCb83g9{rLCj=ras@O_4T8V;0O0l-Rc3VQ(AeZtWJ$nfM}7GEUYDm?7c ze5;#QDF#vS`iE>H3Hbq%2Tq9{D5W7)OS46Z^oOO@DnP1-NG5T^44A?%WwZgR^-sy0 z!U=#iwIP|~I>h>Mvi$d!4nPlFnP1CQfF3j|$P~sZOa|z^b+sH=@gX`Pz!*F-6(S~F zh`u<95Rai{>p75|vJX+!f{@}qG6^EaW^w``gG2ORvj9?Z1@!=i5Y>8^>N-Omm~bPi zI#>ZzX379qm%C*MFmhl<{xGz6Q1iSNaV;$X8vsn1!jh{PVh1uUw~+gf8pj|K2wUm^ ztd;(^c5&UD_7RcIAr+tuz^Ua=72-za3(dTumMosZ)p9tm1Er1wn~e8g`r*OTJuThi z?zJsAHTtJx(-|$Fh0p>h1BenbH_`2gC-3&b>0>rb9BB^X+NJ{^zYoIH$a3e_MD*d2 zRx^PD$=HP*n8N*584e8tY^-lIb-mgf4A|Mzt6g<<$U~!@6@w=e?Ai$O`qeY==Jm^# z?s56zd7#R(_9qq!)q2Sz;d17zE>NC}D^ zibbfr09VV>`qXFJ+wN&#zPlr^c*t)lF1~Dt=?IU=USO zQR^SWgFYMPmnut&O`h3*g>`#v_W02OyE5th(2|`=7y&iRM+Dn z>p9dmZ0ce!>jvx6+eah2PmGGOUA7!=*i|&qeJqEpuXBs;{Mnn!+dMkMdd%9$lYb7d z&aqCi##jdnnnQlE7FZuxuUJ2H61Z~We%26cpr8P^1BgG9&g(@ldeMtsG)^Ma!?QE1 be*z2u(+b1W3dTl!00000NkvXXu0mjf*$ELm literal 0 HcmV?d00001 diff --git a/ExaltedDice/res/drawable/timepicker_down_selected.9.png b/ExaltedDice/res/drawable/timepicker_down_selected.9.png new file mode 100755 index 0000000000000000000000000000000000000000..b45db62121d416b1b97143c80d67cae4b3e4503c GIT binary patch literal 1170 zcmV;D1a13?P)BocMpC5B?ljvTs&w9ArXQY5z!E$Cgim{(`9wf zY<9NOvpb#aqC2xiidmZJ+4OJ!)zw`+0F5z%*0YBE&uD0SMN<#2K_CDGJ5j=Ic`zP3 z^4J{*z;ysGKX}cJ*W-71#(ryy0Db@pB2f+28HcBajS3!kuJJB2z|9qalFtAcqM(Rf z4gpGrjs(c?3Px092DtqjpjfH^tQqkcRv*Lwih_j#i)$f3Kd!)hPJs%b3SS$5!8Ust zpnzPPOd#ln`5-Mo3grA3d0l|i;)Lpi7coGG#~7f60!4`-mNbB*@uG}L4KqJ%#zRNSOF9<^@--qf$vwk;PFh)zMgUK>;_yoyw$wS9I20lEkIEL z*(`hh?I2t{>A_I{-XQ+k@L_tZ56+9l=0!1vBC-QWk;exLqn>IPW-v%06R zkVU3mNFJPR-N0NIh&Eod7l5F3Y;ZEUHF^oA-o4q^Gj5Dt1zLR3upiY3+7_S=vRONi zA%6je$M5Xx8Kv0?2paXnqG5b>>d9Wx4@D+U4OU>Vw4nUIO1YW>6Is**h@nII3Wg0| zMr#SC+5*Knq}dBYtdp^0R*#C&@EK#CdN1sRDNa^$^fF*3_r(e7Q&%@U5+TPXiMSra z3)o3*h$&u;ZemjT=iqkQF#1Dg;3=0(($9fzCwB;s^C(_TptMC*Y9V6Ugtv3WaHf(+ znr?xabl51cD|(&53paxCvk)C#OP2Q0@X=I}hVW2bDbNaFXLtr6Tz-bov_%@P3><4# z@zhjW7LpA>ls9t-BX=b2JP&hLQAG)mRfw+5n+aZ|Kv_w^oWGe+elyFn31P3m>XXx5 z1TdEcRoZ#AO(ha9y#jv}(VHt2a1doppOXj?~ya~!^8kd&^`)-t*Ssyq7JI? zT^IQA*!YC3dOTr&sg(_O*#Y+3>|>LUM!L_O=o#pAaWIbnc>?<~{dIkI + + + + + + + + + + + diff --git a/ExaltedDice/res/drawable/timepicker_input_disabled.9.png b/ExaltedDice/res/drawable/timepicker_input_disabled.9.png new file mode 100755 index 0000000000000000000000000000000000000000..f73658e73e57dda68df78005dca55c4fc53280d9 GIT binary patch literal 280 zcmeAS@N?(olHy`uVBq!ia0vp^0YI$D!3HE3*{oXvq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~-c747nLaSW-r_2$+_t|kYW0}qX*tOd54wI8^e{>f3QN?^Xu zA=`qY?aOj@C>931{O$YcxxmjI&H~Oi>K;#%*YiHJ&i8W6uYLBcwOUN4{_SgTD&r}aE YT!zopr01@D8t^fc4 literal 0 HcmV?d00001 diff --git a/ExaltedDice/res/drawable/timepicker_input_normal.9.png b/ExaltedDice/res/drawable/timepicker_input_normal.9.png new file mode 100755 index 0000000000000000000000000000000000000000..8032adac1441f1e7e8467d6969cb724a612a08aa GIT binary patch literal 582 zcmV-M0=fN(P){;gwEXCn{NqB)z0W+)_m|7X zeDHmrJkJvevFkc&+t#!e18^Y_{{$Ygu4^ia!dZc| zTCEK6D2gZu0+SK}Hcex)sw#7J1_Td zz~FklTEAum$YsmwLt-A36ufvaNHB0#AYd^xsdFHY7a(s5XcV9=r6~~Vn;O3YoR|ln z0#IrRKUIMeS7Db5RDiDl2v`cRa~l7s0*4SK17sGn6?m(IcizT4q(I%qJg|)c?S4uu zVT>6n>~oj}Pc%naLi-l52rfd2c-dY6;C+zphWfE!$1MP z0w5a;*;Iq8!~<1kz-?!M?27|D*t__2RvJJySc1if!P2t=grN|AICKJUoK$lW5&}Yk ziL(MvrxTseXX6iKpR`nuG}MP=)4dbGEXycOQ{5%^;&?n-@82UUX-lyan{NRI0OgQN UP_?K6b^rhX07*qoM6N<$f@t3I1^@s6 literal 0 HcmV?d00001 diff --git a/ExaltedDice/res/drawable/timepicker_input_pressed.9.png b/ExaltedDice/res/drawable/timepicker_input_pressed.9.png new file mode 100755 index 0000000000000000000000000000000000000000..30d8d5fa15af4797e0d4a1183ef4b35f9abb5814 GIT binary patch literal 604 zcmV-i0;BzjP) zhwut|10VH-`sfYx3O@L#M-T!UgRmXj?h3oG!P@QvaXLw%*+8@N<^N}<0**iEm|sq{ zJbR$q>x%?&Kk(-6(R^M01`y!=1yY175MVh?Wa0qMHrxBB4;T*+5P5+iQ#9tE1Xt&y z0DxbM%{I@6aC#y^FaxL!z_&%wVA0089pGxY*^b8(m`n^n!3>}VSfgmL@Kzw{?LHey z7>pE1$xDJoL6EHsiz&nbRDB7(OoC+QVPQP1`qW?%1Q4w9q>(Z+3%jmqa*qdSiXV#d zFjoBR>~3=JPJzq-y30?n0*j^sOA9juXcbrl0Ms?=&c0?LI|Y`x>-ZXoj1?GaVMx`at`Hn zC$z1ITW9vnS@|49?l5G=kG$qNKLy(B3^J3Th6n}L#iog`g>CK_36MMw`hN>oT zT5r~C?H0Ehs0%9d76AaU_NUo=4N4*i$q%5-{p>J6Yy~KL+kO80%67)f?ME*_fvTSd q literal 0 HcmV?d00001 diff --git a/ExaltedDice/res/drawable/timepicker_input_selected.9.png b/ExaltedDice/res/drawable/timepicker_input_selected.9.png new file mode 100755 index 0000000000000000000000000000000000000000..874f18f2bb021d7c984c49089488c6a6d3e6cd2f GIT binary patch literal 517 zcmV+g0{Z=lP)gC&qDV-2 z0K9=a{D5P50I%Z60gn6tp1}p45TcYzi{b@Gvg4>G7(0kcyDO!&sx<0Ock5LOaQK0T z{NaS>wMV>Lp99A}*46#f*VBdjn)IIe{=!;;;RoElu}m6ZYnKlvH&B)(2q8$pAR=^K z2bZtc5rDgmUDkCCRaKD$EQ$i)c{6*OAMj&43QGxjoqT<8aU#UvL>fb0H)+ z9ERlV2NblcZ<4oQz<&UAwibP3vG045H&pfU(>Ch`6waHPrm=spPy=k+7Rvdwg%>bi zjqB6fGqNMfv3^)ZRG>WK`7UV=lm)|t#&2#jBiro9rvL*0a=6CWO2M0;00000NkvXX Hu0mjf8xY$? literal 0 HcmV?d00001 diff --git a/ExaltedDice/res/drawable/timepicker_up_btn.xml b/ExaltedDice/res/drawable/timepicker_up_btn.xml new file mode 100755 index 0000000..5428aee --- /dev/null +++ b/ExaltedDice/res/drawable/timepicker_up_btn.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + diff --git a/ExaltedDice/res/drawable/timepicker_up_disabled.9.png b/ExaltedDice/res/drawable/timepicker_up_disabled.9.png new file mode 100755 index 0000000000000000000000000000000000000000..327b0b5ad926c56f5c67259fe612527a1f7112b1 GIT binary patch literal 491 zcmVUD{k{l`FwJ}bH8zye*w7UzKP>_?KsZLFpTSSq*qndHqY~y zFbp60WzPLN1Yo1MyCg~OEz4TLq%6I%+yp`Jz?VuDb-bezi>OApjSqY1%;6ua?PT2tXaU_LdHS04N{88UV)uBmn$BzzbO|TolD+ zmSx{r)bqRz$A}MAW+2G`@CV-RwQTneutesnKuL=L5Eh1oXQjZC#+YtY`K{74y%oJb zam119D0hr_GI7L#g=e)y8vDuc9m*c%n%T8)e(laY-}j$Y*}{l1n1Kk=N-Gcm0T2Lt z@nqttGCIacu|y6<94wKUSs4GyjRZ)@fv_;PFphGtFcb&{POm_M0!J#4>RSA~2@&Bz hluj`xp)98GC9G>HON6fMv(1~J}2WZ>5&+EzZh8Gy!pv` zYTbd0OL7;S+YJ#Ebpmn#GB9D$$IJQSnH0k>U;qN~NDVv?0Q(&p4&X3>RH!Hb zTMA@i`15--&%yv|STGS4fdBuEh8w()`^P|X05XpTAkF|}#ukA8(V8<%|No8#96SL3 z5=epn|NmzMg3&BYZWcxhyg?Iy&z?QwzJC3>D2T18srgz;O6u!i3_xtn7{-4(Kk#+d>chfEe8%FP(2f1?42l7&ePz|kyBN){eXfz(fd zO#kULTY%hDAq4jB-K&62oYqYow6Gwm83V3FV3=M_m4P&aP!>iC3nD9#(fKMw7A7kN z{)Z%8T4!ZY_8Sal5X!{GW_UWOT|IIRpoBEj%Q` zkDM}aG}v&0(EuC`z#$NTjDx|Y$juX4H&sXg#Px*-gG=!>aYnQ7Fw4UKM+1=j0K_^g zH#kbcL0Re%H7mzB8h|(hkjP48G!x@WbHoklj|L#lAR{gXGP5E$uE!$kM|1$Pl92*g z*hUi`kqv1^tO3Z%J{nTQ_Cy%};~2XF*3P4YT1WuY+`}dg5MThEz3ltmO$v(u0000< KMNUMnLSTXl7dOuU literal 0 HcmV?d00001 diff --git a/ExaltedDice/res/drawable/timepicker_up_normal.9.png b/ExaltedDice/res/drawable/timepicker_up_normal.9.png new file mode 100755 index 0000000000000000000000000000000000000000..dcd26e0115e0e46357b5c5c141cb96ae0e1e8e9b GIT binary patch literal 989 zcmV<310wv1P)8v^^wxth>qVeEhyQZ*~ND8tcK!vzPeHug|mz*W$z%i7ya;<5NC=iC+`{ zP5h4=fGOf{udc2>B@&7EhGDGvk>2Cu-rjx=g+iOX zp1)ItrfG10fBz#Ei+v%d--$QaJZkdPSFKh*nx?r)zJdN-K81+zaO}tenJh0aU)ulz z58xsR+jj_$g7Y&#dPF9JIRT~tTp)k2*6ntE4UYqHZIIrk0yGdB>wX7FAtDV2+a~;CE2te6j&(F`{@bJ)T zmr5nb=kqE<)d`?34AAR3@bvT)wzjq)nM}gvbgD~z-jPg!3~GQkj-ZM z4{4e}>rz$9b0}kk02&k^t3uU=z$i34(q*L=DjcZKT@J*Do~A&VaIyb~hX<>TM_CG- zrb4*>E7Z-4JbTsz){QNw`VljLV zH%t`=2M188RL1Tt6bg{b<)kanO&zE#gilURtih+#Y3_BZz<4}v`O3=5$n{pM1?6%X z*4Nin)2XQ8VZ1_%kaG4+t z!x${P<20y(L~QB}Hd0CE**-<31GRG!ynA1^Io zoB--DzAL9gU`{3$!XovNPfchR)&ppcxlwFajx8YVGm_u(;VipydMFec7LdU&6Z&tY zv6vSII5#&pQdIg~fe6rHV_o9{#7*r$ed8+RDR7ds0(t_h{s}Mu#Lr?Bm;wV400000 LNkvXXu0mjf*EPs! literal 0 HcmV?d00001 diff --git a/ExaltedDice/res/drawable/timepicker_up_pressed.9.png b/ExaltedDice/res/drawable/timepicker_up_pressed.9.png new file mode 100755 index 0000000000000000000000000000000000000000..7dac77868749d88becf9c7d02c47edc68b0b4d64 GIT binary patch literal 1433 zcmV;K1!nq*P))HxC%ta3MyGkVTEI z1SKj8>`eE2WxbD{>6v*m+a0%ivORC9Om|OD)BT%&RlQd=0P8adHs08X_gue$W8Rx% z+sU?_ZFWle++w@Nw!(I!2*3x~9{y$N)9`^4FCimz@77R@d1e0 z{big1IE@*?0t9Nn{9JUvPse61CZ$7M$865_C($i!AO8Ou2cCa2g8Ozf;hPl&i+h$!UAFbZ zwD1f#PNEtr76E9~$M7iWWE2Q}u3WYPXPN+yKD5bfHw4(2TvZ%&DkP&oWkJgP00Rp! zwPaX%6~sNob1#`#x0SrD5?Ns)?kN!ia&y7BKn!GP`T@w8nn~w{NxW_v2ofeTB!6)-wqITnOS7V!NRftYQN||W+zNEF7iW_gf8LC{ z3cP-!Q?UXEmcy(&VgLV}F;H1>=B7)$@$;7(@ZOo`(DALa0nE)Rqdcnu1#f<~4K6LO z4xM}Il{OsQ8<*+KCIq?_ZO*l@v^9jX6?ppVEzsH*!2Sm!@B2w?lgN%)WQ*X5-TmkN z^{;}ZA7`Mo`+DgG8I(l;X5f_x@b1k3d**|#s}>zwHfh81!;CDdK(fIzwX!nsYcD?o z7cXA;U)Olyxu=2dd|96S(qcRnRG?l%lNwRYTBot^t{>pBW3PJO`}mX3`}SWye$;zj z=hw3!%bH@jG7GAL3QW`YP%C7eZ#4P)iZS1~bae(E*=28UwM}sQ+Yc%)GGLYi6ah&6 z^Pou##aT?I6KPrTO;Dczv&V7*#DR77Bvv8}P`U6S)dar5!6h;lbm45Ff(9>06)8}q z+f+R?=yf-}Y{mgZ*Ag|=92}ByB~A4PFXEM3enerWNL(?K~Yl8>c@|zyfPw6b(R;=oz6~ z46oHxDj^Zxz6$LtAN3w22&(nlZat74((q`ERN!D&jsb=&!v?F5U1&`SZuHhBj@{SY zI16xeQ)%!D0x`575Xv7W>-t+6Po_d43=7SqfC~q<52`=dt!H74RF_AM?in2m*B8#0 zM068HlQ)Gh@9$!!W!Qd*QK405zOEc{%1JXY5ss91z1dmepm3R36ac8hA4RUo9H1vl z)mLyHIRQ48rY6X?WH#crgq(c nV_@iaVJs-mo{Q1Ayq z{DqoLL^c|d$=bhJZ zi+yu!``PB%Zl6*yRi(t7%V^{_e;|<>|$Sq24DbDD3=YByN`afo&g9&0QWD>bPmC_ zD*$mC;50@E2M~G^7H8xk9}{3Zfb+6VU42*!7c7bYOL1vnF;K1!7u-9-vWR zY_|vH04lG(*awod>ryjyjSqgAg{STd;lQ0O_^zX2B|hIwB>;zAnRu>&HV}&{0DIPj zDM_T8_te|M0G1Zpc0DvgP)&Na?<5+*#BNGwn3M!4%sIxun1XyAp#g}RADoI^24I#t zZg^P40ZWs~UdkmBUT#sMl;V4NsW zjRjx=Q9z|cI#FPv#4!NexZ1PeOuP7R7xe6S0N$7aRlS4v+NBUqoonT`&&~*#YqJ8q z3!B-{o9Fhzx9it)$DVw66IS>2YIcWe3KXOrI6I505#ZThcf-nE0uIhch5O^!4Z!=_ z$QHpv3&Y1<=Je*P|JtxJcd52}B$i-c80e}1y+Mt|m^+xqy?ew!X%*XUX$;+c))vi% zIOG5Zh2<b=vE^Ftk@V2ytE2+^C)XS}4tCGOgRj0=xbO6t zvqS$Md+n9N<9gqJ0=nklMuVAbNq{hbM>R%Zb@3-_MeUpQHaxJ`-Cidqxc=F@W2rTu zXFyN^V0r)@SB*t;1XIc<(wtO}t=5A>Sxrd=;sBmm<|>8_^hOzgy1(AggTxUt63?SN zz`)J_tZ9EC%3QeS9%)Jgq<#k)hX*MZBMMk_6sWH!43jc&hj=y2oyFY#kO73bPO61>(*g~p>*eX94b^!TU^KuDw22{9aUPdDon2oW*(iV + + + + + + + + + \ No newline at end of file diff --git a/ExaltedDice/res/layout/dice_selector.xml b/ExaltedDice/res/layout/dice_selector.xml index 8fe85d2..9122535 100644 --- a/ExaltedDice/res/layout/dice_selector.xml +++ b/ExaltedDice/res/layout/dice_selector.xml @@ -4,19 +4,17 @@ android:layout_height="wrap_content" android:orientation="horizontal" > - + android:layout_height="wrap_content" /> - + android:layout_height="wrap_content" /> - diff --git a/ExaltedDice/res/layout/main.xml b/ExaltedDice/res/layout/main.xml index 9942ae1..b37e8e9 100755 --- a/ExaltedDice/res/layout/main.xml +++ b/ExaltedDice/res/layout/main.xml @@ -16,7 +16,7 @@ + android:layout_weight="2.5" > + + + + + + + + + + + \ No newline at end of file diff --git a/ExaltedDice/res/values/attrs.xml b/ExaltedDice/res/values/attrs.xml index 68a68fc..14a500b 100644 --- a/ExaltedDice/res/values/attrs.xml +++ b/ExaltedDice/res/values/attrs.xml @@ -1,10 +1,19 @@ - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ExaltedDice/src/com/TwentyCode/android/ExaltedDice/ExaltedDice.java b/ExaltedDice/src/com/TwentyCode/android/ExaltedDice/ExaltedDice.java index 966e376..24724a2 100755 --- a/ExaltedDice/src/com/TwentyCode/android/ExaltedDice/ExaltedDice.java +++ b/ExaltedDice/src/com/TwentyCode/android/ExaltedDice/ExaltedDice.java @@ -44,16 +44,20 @@ public class ExaltedDice extends Activity implements OnClickListener, OnItemClic private ListView mListView; private NumberPicker mNumberPicker; private NumberPicker mDPicker; + private NumberPicker mModPicker; private Database mDb; private String mGameName; private long mGameId; private RollHistoryDatabaseAdapter mListAdapter; private SharedPreferences mSettings; private String[] mModValues; - private NumberPicker mModPicker; private ProgressBar mRollProgress; private View mRollButton; private boolean isRolling = false; + private com.TwentyCode.android.ExaltedDice.NumberPicker mCompatDPicker; + private com.TwentyCode.android.ExaltedDice.NumberPicker mCompatNumberPicker; + private com.TwentyCode.android.ExaltedDice.NumberPicker mCompatModPicker; + private boolean isCompat = false; /** * Applies the presets from the provided roll @@ -63,14 +67,66 @@ public class ExaltedDice extends Activity implements OnClickListener, OnItemClic private void applyRollPresets(long id) { ContentValues roll = mDb.getGameHistoryInfo(mGameName, (int) (id)); try{ - mNumberPicker.setValue(roll.getAsInteger(Database.KEY_NUMBER)); - mDPicker.setValue(parseD(roll.getAsString(Database.KEY_D_TYPE))); - mModPicker.setValue(parseMod(roll.getAsString(Database.KEY_MOD).replace("'", ""))); + if(isCompat){ + mCompatNumberPicker.setValue(roll.getAsInteger(Database.KEY_NUMBER)); + mCompatDPicker.setValue(parseD(roll.getAsString(Database.KEY_D_TYPE))); + mCompatModPicker.setValue(parseMod(roll.getAsString(Database.KEY_MOD).replace("'", ""))); + } else { + mNumberPicker.setValue(roll.getAsInteger(Database.KEY_NUMBER)); + mDPicker.setValue(parseD(roll.getAsString(Database.KEY_D_TYPE))); + mModPicker.setValue(parseMod(roll.getAsString(Database.KEY_MOD).replace("'", ""))); + } } catch(NullPointerException e){ - mModPicker.setValue(parseMod("+0")); + if(isCompat) + mCompatModPicker.setValue(parseMod("+0")); + else + mModPicker.setValue(parseMod("+0")); } } + /** + * Initializes compat pickers for api < 11 + * @author ricky barrette + */ + private void initCompatPickers() { + isCompat = true; + + mCompatDPicker = (com.TwentyCode.android.ExaltedDice.NumberPicker) findViewById(R.id.d_Picker); + mCompatDPicker.setDisplayedValues(mDiceValues); + mCompatDPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); + + mCompatNumberPicker = (com.TwentyCode.android.ExaltedDice.NumberPicker) findViewById(R.id.number_Picker); + mCompatNumberPicker.setRange(1, 999); + mCompatNumberPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); + + mCompatModPicker = (com.TwentyCode.android.ExaltedDice.NumberPicker) findViewById(R.id.mod_Picker); + mCompatModPicker.setDisplayedValues(mModValues); + mCompatModPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); + } + + /** + * Initializes native number pickers api > 11 + * @author ricky barrette + */ + private void initPickers() { + mDPicker = (NumberPicker) findViewById(R.id.d_Picker); + mDPicker.setMinValue(0); + mDPicker.setMaxValue(mDiceValues.length -1); + mDPicker.setDisplayedValues(mDiceValues); + mDPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); + + mNumberPicker = (NumberPicker) findViewById(R.id.number_Picker); + mNumberPicker.setMaxValue(999); + mNumberPicker.setMinValue(1); + mNumberPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); + + mModPicker = (NumberPicker) findViewById(R.id.mod_Picker); + mModPicker.setMinValue(0); + mModPicker.setMaxValue(mModValues.length -1); + mModPicker.setDisplayedValues(mModValues); + mModPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); + } + /** * also implemented OnClickListener * @@ -113,13 +169,21 @@ public class ExaltedDice extends Activity implements OnClickListener, OnItemClic Log.i(TAG, "onCreate()"); setContentView(R.layout.main); + mSettings = getSharedPreferences(Settings.SETTINGS, Context.MODE_WORLD_WRITEABLE); + + mDiceValues = getResources().getStringArray(R.array.dice_types); + mModValues = getResources().getStringArray(R.array.mods); + /* * The following is for api 11 and up + * else use compat methods */ if(Integer.valueOf(android.os.Build.VERSION.SDK) > 11){ ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); - } + initPickers(); + } else + initCompatPickers(); Intent i = this.getIntent(); if(i != null) @@ -129,32 +193,10 @@ public class ExaltedDice extends Activity implements OnClickListener, OnItemClic this.setTitle(mGameName); } - mSettings = getSharedPreferences(Settings.SETTINGS, Context.MODE_WORLD_WRITEABLE); - - mDiceValues = getResources().getStringArray(R.array.dice_types); - mModValues = getResources().getStringArray(R.array.mods); - mListView = (ListView) findViewById(R.id.list); mListView.setOnItemClickListener(this); mListView.setStackFromBottom(true); - mDPicker = (NumberPicker) findViewById(R.id.d_Picker); - mDPicker.setMinValue(0); - mDPicker.setMaxValue(mDiceValues.length -1); - mDPicker.setDisplayedValues(mDiceValues); - mDPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); - - mNumberPicker = (NumberPicker) findViewById(R.id.number_Picker); - mNumberPicker.setMaxValue(999); - mNumberPicker.setMinValue(1); - mNumberPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); - - mModPicker = (NumberPicker) findViewById(R.id.mod_Picker); - mModPicker.setMinValue(0); - mModPicker.setMaxValue(mModValues.length -1); - mModPicker.setDisplayedValues(mModValues); - mModPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); - mRollProgress = (ProgressBar) findViewById(R.id.roll_progress); mRollButton = findViewById(R.id.roll_button); @@ -183,6 +225,40 @@ public class ExaltedDice extends Activity implements OnClickListener, OnItemClic return true; } + @Override + public void onDatabaseInsertComplete() { + isRolling = false; + this.runOnUiThread(new Runnable(){ + @Override + public void run(){ + mRollProgress.setVisibility(View.GONE); + mRollButton.setEnabled(true); + refresh(); + } + }); + } + + @Override + public void onDatabaseUpgrade() { + //do nothing + } + + @Override + public void onDatabaseUpgradeComplete() { + // do nothing + + } + + @Override + public void onDeletionComplete() { + this.runOnUiThread(new Runnable(){ + @Override + public void run(){ + refresh(); + } + }); + } + /** * rolls same amount of dice as previous roll * @author ricky barrette @@ -220,29 +296,31 @@ public class ExaltedDice extends Activity implements OnClickListener, OnItemClic return super.onOptionsItemSelected(item); } } - - /** - * (non-Javadoc) - * @see android.app.Activity#onPause() - */ - @Override - protected void onStop() { - mDb.close(); - super.onStop(); + + @Override + public void onRestoreComplete() { + // do nothing } + /** - * resorts application state after rotation - * @author ricky barrette - */ - @Override - public void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - mDPicker.setValue(savedInstanceState.getInt("d")); - mNumberPicker.setValue(savedInstanceState.getInt("number")); - mModPicker.setValue(savedInstanceState.getInt("mod")); - } + * resorts application state after rotation + * @author ricky barrette + */ + @Override + public void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + if(isCompat){ + mCompatDPicker.setCurrent(savedInstanceState.getInt("d")); + mCompatNumberPicker.setCurrent(savedInstanceState.getInt("number")); + mCompatModPicker.setCurrent(savedInstanceState.getInt("mod")); + } else { + mDPicker.setValue(savedInstanceState.getInt("d")); + mNumberPicker.setValue(savedInstanceState.getInt("number")); + mModPicker.setValue(savedInstanceState.getInt("mod")); + } + } - /** + /** * (non-Javadoc) * @see android.app.Activity#onResume() */ @@ -252,15 +330,41 @@ public class ExaltedDice extends Activity implements OnClickListener, OnItemClic applyRollPresets(mDb.getGameRollCount(mGameId)); if(mSettings.getBoolean(Settings.KEY_ROLL_MOD, true)){ - mModPicker.setVisibility(View.VISIBLE); + if(isCompat) + mCompatModPicker.setVisibility(View.VISIBLE); + else + mModPicker.setVisibility(View.VISIBLE); } else { - mModPicker.setVisibility(View.GONE); - mModPicker.setValue(parseMod("+0")); + if(isCompat){ + mCompatModPicker.setVisibility(View.GONE); + mCompatModPicker.setValue(parseMod("+0")); + } else { + mModPicker.setVisibility(View.GONE); + mModPicker.setValue(parseMod("+0")); + } } super.onResume(); } + + /** + * saves application state before rotation + * @author ricky barrette + */ + @Override + public void onSaveInstanceState(Bundle savedInstanceState) { + if(isCompat){ + savedInstanceState.putInt("d", mCompatDPicker.getCurrent()); + savedInstanceState.putInt("number", mCompatNumberPicker.getCurrent()); + savedInstanceState.putInt("mod", mCompatModPicker.getCurrent()); + } else { + savedInstanceState.putInt("d", mDPicker.getValue()); + savedInstanceState.putInt("number", mNumberPicker.getValue()); + savedInstanceState.putInt("mod", mModPicker.getValue()); + } + super.onSaveInstanceState(savedInstanceState); + } - /** + /** * (non-Javadoc) * @see android.app.Activity#onStart() */ @@ -273,15 +377,13 @@ public class ExaltedDice extends Activity implements OnClickListener, OnItemClic } /** - * saves application state before rotation - * @author ricky barrette + * (non-Javadoc) + * @see android.app.Activity#onPause() */ @Override - public void onSaveInstanceState(Bundle savedInstanceState) { - savedInstanceState.putInt("d", mDPicker.getValue()); - savedInstanceState.putInt("number", mNumberPicker.getValue()); - savedInstanceState.putInt("mod", mModPicker.getValue()); - super.onSaveInstanceState(savedInstanceState); + protected void onStop() { + mDb.close(); + super.onStop(); } /** @@ -296,8 +398,8 @@ public class ExaltedDice extends Activity implements OnClickListener, OnItemClic return i; return 0; } - - /** + + /** * Parses the string mod to the appropriate value * @param mod * @return value for d picker @@ -332,7 +434,7 @@ public class ExaltedDice extends Activity implements OnClickListener, OnItemClic }); builder.show(); } - + /** * Refreshes the list view * @author ricky barrette @@ -366,7 +468,10 @@ public class ExaltedDice extends Activity implements OnClickListener, OnItemClic resultsString.append(getString(R.string.total)+ total); if(mSettings.getBoolean(Settings.KEY_ROLL_MOD, true)) - resultsString.append(getString(R.string.total_plus_mod)+ (total + Integer.parseInt(mModValues[mModPicker.getValue()].replace("+", "")))); + if(isCompat) + resultsString.append(getString(R.string.total_plus_mod)+ (total + Integer.parseInt(mCompatModPicker.getValue().replace("+", "")))); + else + resultsString.append(getString(R.string.total_plus_mod)+ (total + Integer.parseInt(mModValues[mModPicker.getValue()].replace("+", "")))); if(mSettings.getBoolean(Settings.KEY_CALC_SUCCESSES, true)) resultsString.append(getString(R.string.sucesses)+ successes(roll)); @@ -399,11 +504,20 @@ public class ExaltedDice extends Activity implements OnClickListener, OnItemClic int rollId = mDb.getGameRollCount(mGameId) +1; ContentValues roll = new ContentValues(); - roll.put(Database.KEY_D_TYPE, mDiceValues[mDPicker.getValue()]); - roll.put(Database.KEY_NUMBER, mNumberPicker.getValue()); - roll.putAll(results(mNumberPicker.getValue())); - roll.put(Database.KEY_MOD, DatabaseUtils.sqlEscapeString(mModValues[mModPicker.getValue()])); + if(isCompat){ + roll.put(Database.KEY_D_TYPE, mCompatDPicker.getValue()); + roll.put(Database.KEY_NUMBER, mCompatNumberPicker.getCurrent()); + roll.putAll(results(mCompatNumberPicker.getCurrent())); + roll.put(Database.KEY_MOD, DatabaseUtils.sqlEscapeString(mCompatModPicker.getValue())); + } else{ + roll.put(Database.KEY_D_TYPE, mDiceValues[mDPicker.getValue()]); + roll.put(Database.KEY_NUMBER, mNumberPicker.getValue()); + roll.putAll(results(mNumberPicker.getValue())); + roll.put(Database.KEY_MOD, DatabaseUtils.sqlEscapeString(mModValues[mModPicker.getValue()])); + } + + mDb.updateGame(mGameId, mGameName, roll, rollId); } @@ -422,7 +536,10 @@ public class ExaltedDice extends Activity implements OnClickListener, OnItemClic int[] roll = new int[times]; Random random = new Random(); for (int i = 0; i < times; i++) { - roll[i] = random.nextInt(Integer.parseInt(mDiceValues[mDPicker.getValue()].substring(1))) + 1; + if(isCompat) + roll[i] = random.nextInt(Integer.parseInt(mCompatDPicker.getValue().substring(1))) + 1; + else + roll[i] = random.nextInt(Integer.parseInt(mDiceValues[mDPicker.getValue()].substring(1))) + 1; } return roll; } @@ -470,43 +587,4 @@ public class ExaltedDice extends Activity implements OnClickListener, OnItemClic Vibrator vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); vib.vibrate(milliseconds); } - - @Override - public void onDatabaseUpgradeComplete() { - // do nothing - - } - - @Override - public void onDeletionComplete() { - this.runOnUiThread(new Runnable(){ - @Override - public void run(){ - refresh(); - } - }); - } - - @Override - public void onRestoreComplete() { - // do nothing - } - - @Override - public void onDatabaseUpgrade() { - //do nothing - } - - @Override - public void onDatabaseInsertComplete() { - isRolling = false; - this.runOnUiThread(new Runnable(){ - @Override - public void run(){ - mRollProgress.setVisibility(View.GONE); - mRollButton.setEnabled(true); - refresh(); - } - }); - } } \ No newline at end of file diff --git a/ExaltedDice/src/com/TwentyCode/android/ExaltedDice/NumberPicker.java b/ExaltedDice/src/com/TwentyCode/android/ExaltedDice/NumberPicker.java new file mode 100755 index 0000000..8f7409a --- /dev/null +++ b/ExaltedDice/src/com/TwentyCode/android/ExaltedDice/NumberPicker.java @@ -0,0 +1,488 @@ +/** + * Number Picker.java + * + * @author Google + * @author ricky barrette + * @author Twenty Codes + * + * Copyright (C) 2012 Rick barrette + * Copyright (C) 2012 Twenty Codes + * 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. + */ + +package com.TwentyCode.android.ExaltedDice; + +import android.content.Context; +import android.content.res.TypedArray; +import android.os.Handler; +import android.text.InputFilter; +import android.text.InputType; +import android.text.Spanned; +import android.text.method.NumberKeyListener; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnFocusChangeListener; +import android.view.View.OnLongClickListener; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; + +/** + * This class has been pulled from the Android platform source code, its an internal widget that hasn't been + * made public so its included in the project in this fashion for use with the preferences screen; I have made + * a few slight modifications to the code here, I simply put a MAX and MIN default in the code but these values + * can still be set publicly by calling code. + * + * @author Google + */ +public class NumberPicker extends LinearLayout implements OnClickListener, OnFocusChangeListener, OnLongClickListener { + + /** + * This class is used to filter the input from a keyboard + */ + private class NumberPickerInputFilter implements InputFilter { + public CharSequence filter(CharSequence source, int start, int end, + Spanned dest, int dstart, int dend) { + if (mDisplayedValues == null) { + return mNumberInputFilter.filter(source, start, end, dest, dstart, dend); + } + CharSequence filtered = String.valueOf(source.subSequence(start, end)); + String result = String.valueOf(dest.subSequence(0, dstart)) + + filtered + + dest.subSequence(dend, dest.length()); + String str = String.valueOf(result).toLowerCase(); + for (String val : mDisplayedValues) { + val = val.toLowerCase(); + if (val.startsWith(str)) { + return filtered; + } + } + return ""; + } + } + + /** + * This class + */ + private class NumberRangeKeyListener extends NumberKeyListener { + + @Override + public CharSequence filter(CharSequence source, int start, int end, + Spanned dest, int dstart, int dend) { + + CharSequence filtered = super.filter(source, start, end, dest, dstart, dend); + if (filtered == null) { + filtered = source.subSequence(start, end); + } + + String result = String.valueOf(dest.subSequence(0, dstart)) + + filtered + + dest.subSequence(dend, dest.length()); + + if ("".equals(result)) { + return result; + } + int val = getSelectedPos(result); + + /* Ensure the user can't type in a value greater + * than the max allowed. We have to allow less than min + * as the user might want to delete some numbers + * and then type a new number. + */ + if (val > mEnd) { + return ""; + } else { + return filtered; + } + } + + @Override + protected char[] getAcceptedChars() { + return DIGIT_CHARACTERS; + } + + // XXX This doesn't allow for range limits when controlled by a + // soft input method! + public int getInputType() { + return InputType.TYPE_CLASS_NUMBER; + } + } + + /** + * A simple interface to notify a change has been made + */ + public interface OnChangedListener { + /** + * Called when a change has been made + * @param picker + * @param oldVal + * @param newVal + */ + void onChanged(NumberPicker picker, int oldVal, int newVal); + } + + private static final int DEFAULT_MAX = 200; + private static final int DEFAULT_MIN = 0; + private static final int DEFAULT_VALUE = 0; + private static final boolean DEFAULT_WRAP = true; + private final Handler mHandler; + private final EditText mText; + private final InputFilter mNumberInputFilter; + + private final Runnable mRunnable = new Runnable() { + public void run() { + if (mIncrement) { + changeCurrent(mCurrent + 1); + mHandler.postDelayed(this, mSpeed); + } else if (mDecrement) { + changeCurrent(mCurrent - 1); + mHandler.postDelayed(this, mSpeed); + } + } + }; + + private String[] mDisplayedValues; + protected int mStart; + protected int mEnd; + protected int mCurrent; + protected int mPrevious; + private OnChangedListener mListener; + private long mSpeed = 300; + private boolean mIncrement; + private boolean mDecrement; + private NumberPickerButton mIncrementButton; + private NumberPickerButton mDecrementButton; + private boolean mWrap; + private static final char[] DIGIT_CHARACTERS = new char[] { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' + }; + + /** + * Creates a new NumberPicker + * @param context + */ + public NumberPicker(Context context) { + this(context, null); + } + + /** + * Creates a new NumberPicker + * @param context + * @param attrs + * @author ricky barrette + */ + public NumberPicker(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + /** + * Creates a new NumberPicker + * @param context + * @param attrs + * @param defStyle + * @author ricky barrette + */ + public NumberPicker(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs); + + setOrientation(VERTICAL); + LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + inflater.inflate(R.layout.number_picker, this, true); + mHandler = new Handler(); + InputFilter inputFilter = new NumberPickerInputFilter(); + mNumberInputFilter = new NumberRangeKeyListener(); + mIncrementButton = (NumberPickerButton) findViewById(R.id.increment); + mIncrementButton.setOnClickListener(this); + mIncrementButton.setOnLongClickListener(this); + mIncrementButton.setNumberPicker(this); + mDecrementButton = (NumberPickerButton) findViewById(R.id.decrement); + mDecrementButton.setOnClickListener(this); + mDecrementButton.setOnLongClickListener(this); + mDecrementButton.setNumberPicker(this); + + mText = (EditText) findViewById(R.id.timepicker_input); + mText.setOnFocusChangeListener(this); + mText.setFilters(new InputFilter[] {inputFilter}); + mText.setRawInputType(InputType.TYPE_CLASS_NUMBER); + + if (!isEnabled()) { + setEnabled(false); + } + + TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.numberpicker ); + mStart = a.getInt( R.styleable.numberpicker_startRange, DEFAULT_MIN ); + mEnd = a.getInt( R.styleable.numberpicker_endRange, DEFAULT_MAX ); + mWrap = a.getBoolean( R.styleable.numberpicker_wrap, DEFAULT_WRAP ); + mCurrent = a.getInt( R.styleable.numberpicker_defaultValue, DEFAULT_VALUE ); + mCurrent = Math.max( mStart, Math.min( mCurrent, mEnd ) ); + mText.setText( "" + mCurrent ); + } + + public void cancelDecrement() { + mDecrement = false; + } + + public void cancelIncrement() { + mIncrement = false; + } + + + protected void changeCurrent(int current) { + // Wrap around the values if we go past the start or end + if (current > mEnd) { + current = mWrap ? mStart : mEnd; + } else if (current < mStart) { + current = mWrap ? mEnd : mStart; + } + mPrevious = mCurrent; + mCurrent = current; + + notifyChange(); + updateView(); + } + + /** + * @return the current value. + */ + public int getCurrent() { + return mCurrent; + } + + private int getSelectedPos(String str) { + if (mDisplayedValues == null) { + return Integer.parseInt(str); + } else { + for (int i = 0; i < mDisplayedValues.length; i++) { + + /* Don't force the user to type in jan when ja will do */ + str = str.toLowerCase(); + if (mDisplayedValues[i].toLowerCase().startsWith(str)) { + return mStart + i; + } + } + + /* The user might have typed in a number into the month field i.e. + * 10 instead of OCT so support that too. + */ + try { + return Integer.parseInt(str); + } catch (NumberFormatException e) { + + /* Ignore as if it's not a number we don't care */ + } + } + return mStart; + } + + public String getValue() { + return this.mDisplayedValues[mCurrent]; + } + + protected void notifyChange() { + if (mListener != null) { + mListener.onChanged(this, mPrevious, mCurrent); + } + } + + public void onClick(View v) { + validateInput(mText); + if (!mText.hasFocus()) mText.requestFocus(); + + // now perform the increment/decrement + if (R.id.increment == v.getId()) { + changeCurrent(mCurrent + 1); + } else if (R.id.decrement == v.getId()) { + changeCurrent(mCurrent - 1); + } + } + + public void onFocusChange(View v, boolean hasFocus) { + + /* When focus is lost check that the text field + * has valid values. + */ + if (!hasFocus) { + validateInput(v); + } + } + + /** + * We start the long click here but rely on the {@link NumberPickerButton} + * to inform us when the long click has ended. + */ + public boolean onLongClick(View v) { + + /* The text view may still have focus so clear it's focus which will + * trigger the on focus changed and any typed values to be pulled. + */ + mText.clearFocus(); + mText.requestFocus(); + if (R.id.increment == v.getId()) { + mIncrement = true; + mHandler.post(mRunnable); + } else if (R.id.decrement == v.getId()) { + mDecrement = true; + mHandler.post(mRunnable); + } + + return true; + } + + /** + * Sets the current index + * @param index + */ + public void setCurrent(int index) { + mCurrent = index; + updateView(); + } + + /** + * Sets the current index and notifies listeners + * @param index + */ + public void setCurrentAndNotify(int index) { + mCurrent = index; + notifyChange(); + updateView(); + } + + /** + * Sets the values to display + * @param values + * @author ricky barrette + */ + public void setDisplayedValues(String[] values) { + this.mDisplayedValues = values; + this.mStart = 0; + this.mEnd = values.length -1; + notifyChange(); + updateView(); + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + mIncrementButton.setEnabled(enabled); + mDecrementButton.setEnabled(enabled); + mText.setEnabled(enabled); + } + + public void setOnChangeListener(OnChangedListener listener) { + mListener = listener; + } + + /** + * Set the range of numbers allowed for the number picker. The current + * value will be automatically set to the start. + * + * @param start the start of the range (inclusive) + * @param end the end of the range (inclusive) + */ + public void setRange(int start, int end) { + mStart = start; + mEnd = end; + mCurrent = start; + updateView(); + } + + /** + * Set the range of numbers allowed for the number picker. The current + * value will be automatically set to the start. Also provide a mapping + * for values used to display to the user. + * + * @param start the start of the range (inclusive) + * @param end the end of the range (inclusive) + * @param displayedValues the values displayed to the user. + */ + public void setRange(int start, int end, String[] displayedValues) { + mDisplayedValues = displayedValues; + mStart = start; + mEnd = end; + mCurrent = start; + updateView(); + } + + /** + * The speed (in milliseconds) at which the numbers will scroll + * when the the +/- buttons are longpressed. Default is 300ms. + */ + public void setSpeed(long speed) { + mSpeed = speed; + } + + /** + * Sets the current displayed value by it's index + * @param index + * @author ricky barrette + */ + public void setValue(int index) { + mCurrent = index; + notifyChange(); + updateView(); + } + + /** + * Specify if numbers should wrap after the edge has been reached. + * + * @param wrap values + */ + public void setWrap( boolean wrap ) { + mWrap = wrap; + } + + protected void updateView() { + + /* If we don't have displayed values then use the + * current number else find the correct value in the + * displayed values for the current number. + */ + if (mDisplayedValues == null) { + mText.setText(mCurrent+""); + } else { + mText.setText(mDisplayedValues[mCurrent]); + } + mText.setSelection(mText.getText().length()); + +// mText.resizeText(); + } + + private void validateCurrentView(CharSequence str) { + int val = getSelectedPos(str.toString()); + if ((val >= mStart) && (val <= mEnd)) { + if (mCurrent != val) { + mPrevious = mCurrent; + mCurrent = val; + notifyChange(); + } + } + updateView(); + } + + private void validateInput(View v) { + String str = String.valueOf(((TextView) v).getText()); + if ("".equals(str)) { + + // Restore to the old value as we don't allow empty values + updateView(); + } else { + + // Check the new value and ensure it's in range + validateCurrentView(str); + } + } +} diff --git a/ExaltedDice/src/com/TwentyCode/android/ExaltedDice/NumberPickerButton.java b/ExaltedDice/src/com/TwentyCode/android/ExaltedDice/NumberPickerButton.java new file mode 100755 index 0000000..ea9675d --- /dev/null +++ b/ExaltedDice/src/com/TwentyCode/android/ExaltedDice/NumberPickerButton.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +package com.TwentyCode.android.ExaltedDice; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.widget.ImageButton; + +/** + * This class exists purely to cancel long click events. + */ +public class NumberPickerButton extends ImageButton { + + private NumberPicker mNumberPicker; + + public NumberPickerButton(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + } + + public NumberPickerButton(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public NumberPickerButton(Context context) { + super(context); + } + + public void setNumberPicker(NumberPicker picker) { + mNumberPicker = picker; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + cancelLongpressIfRequired(event); + return super.onTouchEvent(event); + } + + @Override + public boolean onTrackballEvent(MotionEvent event) { + cancelLongpressIfRequired(event); + return super.onTrackballEvent(event); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if ((keyCode == KeyEvent.KEYCODE_DPAD_CENTER) + || (keyCode == KeyEvent.KEYCODE_ENTER)) { + cancelLongpress(); + } + return super.onKeyUp(keyCode, event); + } + + private void cancelLongpressIfRequired(MotionEvent event) { + if ((event.getAction() == MotionEvent.ACTION_CANCEL) + || (event.getAction() == MotionEvent.ACTION_UP)) { + cancelLongpress(); + } + } + + private void cancelLongpress() { + if (R.id.increment == getId()) { + mNumberPicker.cancelIncrement(); + } else if (R.id.decrement == getId()) { + mNumberPicker.cancelDecrement(); + } + } +} diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..cd9c350 --- /dev/null +++ b/project.properties @@ -0,0 +1,13 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "ant.properties", and override values to adapt the script to your +# project structure. + +# Indicates whether an apk should be generated for each density. +split.density=false +# Project target. +target=android-15