From eb3ecee187845149d79b4962e01c590c0a8ed972 Mon Sep 17 00:00:00 2001 From: sekelsenmat Date: Mon, 4 Jul 2011 06:24:41 +0000 Subject: [PATCH] Initial commit of kcontrols git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1732 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- components/kcontrols/help/KControls.chm | Bin 0 -> 540410 bytes components/kcontrols/help/kgrid_manual.pdf | Bin 0 -> 147172 bytes components/kcontrols/kcontrols_readme.txt | 43 + components/kcontrols/kgrid_readme.txt | 192 + components/kcontrols/khexeditor_readme.txt | 92 + components/kcontrols/kicon_readme.txt | 135 + components/kcontrols/source/kcontrols.inc | 285 + components/kcontrols/source/kcontrols.lrs | 30 + components/kcontrols/source/kcontrols.pas | 2825 ++++ components/kcontrols/source/kcontrols.res | Bin 0 -> 912 bytes components/kcontrols/source/kcontrolslaz.lpk | 130 + components/kcontrols/source/kdbgrids.pas | 1495 ++ components/kcontrols/source/kdialogs.pas | 131 + components/kcontrols/source/keditcommon.pas | 413 + components/kcontrols/source/kfunctions.pas | 1365 ++ components/kcontrols/source/kgraphics.pas | 2145 +++ components/kcontrols/source/kgrids.lrs | 101 + components/kcontrols/source/kgrids.pas | 12827 ++++++++++++++++ components/kcontrols/source/kgrids.res | Bin 0 -> 3084 bytes components/kcontrols/source/khexeditor.pas | 5118 ++++++ .../kcontrols/source/khexeditordesign.lrs | 262 + .../kcontrols/source/khexeditordesign.pas | 36 + components/kcontrols/source/khexeditorlaz.lpk | 114 + components/kcontrols/source/khexeditorlaz.pas | 22 + components/kcontrols/source/kicon.pas | 2607 ++++ components/kcontrols/source/kprintpreview.dfm | 1475 ++ components/kcontrols/source/kprintpreview.lfm | 1150 ++ components/kcontrols/source/kprintpreview.lrs | 1447 ++ components/kcontrols/source/kprintpreview.pas | 228 + components/kcontrols/source/kprintsetup.dfm | 427 + components/kcontrols/source/kprintsetup.lfm | 423 + components/kcontrols/source/kprintsetup.lrs | 102 + components/kcontrols/source/kprintsetup.pas | 369 + components/kcontrols/source/kwidewinprocs.pas | 96 + components/kcontrols/source/xpman.res | Bin 0 -> 648 bytes 35 files changed, 36085 insertions(+) create mode 100755 components/kcontrols/help/KControls.chm create mode 100755 components/kcontrols/help/kgrid_manual.pdf create mode 100755 components/kcontrols/kcontrols_readme.txt create mode 100755 components/kcontrols/kgrid_readme.txt create mode 100755 components/kcontrols/khexeditor_readme.txt create mode 100755 components/kcontrols/kicon_readme.txt create mode 100755 components/kcontrols/source/kcontrols.inc create mode 100755 components/kcontrols/source/kcontrols.lrs create mode 100755 components/kcontrols/source/kcontrols.pas create mode 100755 components/kcontrols/source/kcontrols.res create mode 100755 components/kcontrols/source/kcontrolslaz.lpk create mode 100755 components/kcontrols/source/kdbgrids.pas create mode 100755 components/kcontrols/source/kdialogs.pas create mode 100755 components/kcontrols/source/keditcommon.pas create mode 100755 components/kcontrols/source/kfunctions.pas create mode 100755 components/kcontrols/source/kgraphics.pas create mode 100755 components/kcontrols/source/kgrids.lrs create mode 100755 components/kcontrols/source/kgrids.pas create mode 100755 components/kcontrols/source/kgrids.res create mode 100755 components/kcontrols/source/khexeditor.pas create mode 100755 components/kcontrols/source/khexeditordesign.lrs create mode 100755 components/kcontrols/source/khexeditordesign.pas create mode 100755 components/kcontrols/source/khexeditorlaz.lpk create mode 100644 components/kcontrols/source/khexeditorlaz.pas create mode 100755 components/kcontrols/source/kicon.pas create mode 100755 components/kcontrols/source/kprintpreview.dfm create mode 100755 components/kcontrols/source/kprintpreview.lfm create mode 100755 components/kcontrols/source/kprintpreview.lrs create mode 100755 components/kcontrols/source/kprintpreview.pas create mode 100755 components/kcontrols/source/kprintsetup.dfm create mode 100755 components/kcontrols/source/kprintsetup.lfm create mode 100755 components/kcontrols/source/kprintsetup.lrs create mode 100755 components/kcontrols/source/kprintsetup.pas create mode 100755 components/kcontrols/source/kwidewinprocs.pas create mode 100755 components/kcontrols/source/xpman.res diff --git a/components/kcontrols/help/KControls.chm b/components/kcontrols/help/KControls.chm new file mode 100755 index 0000000000000000000000000000000000000000..99182e40ce3b469c81a0aaf19b2688abd9b24c01 GIT binary patch literal 540410 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⁡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 z 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

6e`W?*`ZYO_gnr(!>i%?6 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Ϛ_@Q6xSOt^1zvH2<$f<#Ox9+5wO>M%|?B8k#= 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%0An0yhQD>#Zg~) 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 un%Jmhz{~-{5Tp^bg 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

!uZLj}nr( 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 z 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 ZPwJo4KdF9F{iOOy^^@u+)KC7O0LxW5tC#=) literal 0 HcmV?d00001 diff --git a/components/kcontrols/help/kgrid_manual.pdf b/components/kcontrols/help/kgrid_manual.pdf new file mode 100755 index 0000000000000000000000000000000000000000..a1b7ce224de2f0ef6fb619d926f52c1b8c5ac497 GIT binary patch literal 147172 zcma&sQ*b3f+b-;t72CFL+qRvoIGNZJO`J?@W0FkliEZ1qZF9fxSNs1@zLQ!YXoniKXn~XXx5%e>W)+F4oMpnAx`xtfa1!7%*j*K6pRA zzBUKnqqrU2@8-Xm>NqMU{bfierwyVGE`@0>`<1b;(Pz14zu&$L@0#i7f76mjHKdL% z#uXbGF1IZhwiZszm5<#OYVc`}F1AN4BX_mFO^4DbWQEc?KlTrv|7pa?vD73*E(~Xs zEzB5u416dhO(|1TivT}$)|V^NE4vf%o{Lvd&nSIAnzk;BLz*0?yOup>lr3)5$`xgq z^nczCqmtAst0P`fUt3}4gR=w~4hp0cPj`JH?+>{8;P`jTec7b)bLSLG-v8COWQsW0 z#%|Lp`;jWh>{b9*HAh!AUr=2^_IgtjMJy{=zdyCfh-PAcc{^n3PB$FGILSI9X>(nv zRFoLnS&S~%UNdIbHPhNz6S_)B8`8dD!YoJYZc$@xqou5s(z)p68suu>*vOSdUNK5^ zRK_xF*hkl$GBfZt&AI~Vw9~ts|Q@{QR z71Q6#HW#Mwj{6N_Z#|y-_{uI_V^%%?An@_W6AIPySJL~oORq2Ad=$FYTh`2d#Oyxd z8YaNaSjR->E;+VG{6jx6oqA4)?q^pcH=)_MYNSfAiBvVdzfL;7u{BP6YT}=5E<7*2 z`D7`V{JHBTz!FlBy~KV|T)pw11Ee%vbmHor1<}|)2L$zL6H~GE>Qjd688f@1=Nae3 zV#6z}?n9aAd{*WbQ0GOn`t7DUmEEbrz`qO0HGg!3S`9A>@ljh*=e6!vuI#XZ$Xd(F;%3JbMWKUC1v#M(6h?DlrF(+ykKD zB0J>XGNafePMkr1Sv9F^JGLR0tNPKtQbZSxJWIv5L4okdTJ$^T3A;fU9{1_fSxOt~l+1c1)b&yoYTp2g zojIU@Y*ABd;Q-;i<6aIj8#Sf8zTG-EbUZcgWV zC|zmB3>`FYoF`{n^=^cFPPdQPBhmIAcTaa#Gv^3DspC~tlx7R() zh{3$dH?_*p?PIplUlB5e4#*%EH_iOUG=#Ox&uE$wrw++s{$4bjIy=Cyw4r4$Ls`FP zqL8N86idYMg;kD(i$nSjMu7pd5U#|WULh*jrJaG%qabee3Ei5H*f{7VaKu)uhX@6y?5q(*9g7?1 zla)yNfRFq=EwhUBD6Ru>1A0kVa3e-Fb!Ecic7j0GGZ-U>MXBY<2c?vos^*!qTBhx5 ziSAGP?Q-x)wmY{+Uu8u5tz)~|6Fit{=*j{#xQ)#%e$ep6-Y^GXDGJOkp@B2+_kYXb zYvcz#a0yXW5u(yFr2!8_7{xR(zw;~p&uC5$NcpG{zCQ)p+7|p2@^?CgrOpl?j%)%( z(JzY2IE=z%3ZD3=j>bl8J|`^;lJnQVWD?-*K21i{aqDX+**9pbORgSJBhI!h=L zq(d6l(2USCVa*$Xz@v;^e$u7m_u7WVw)3?Ot6x8M&p~|@6=k(qt{babb zHR;-st($>wllu3}Rz+(tuQo-66$htfsgtG(bUB`T>kP9f%7}h>P3)6ys>|rMGY@9X z%Ch>?Fh%3DT=r+Pzs=r?bCFvV7O#*pY7VO3KG#2PFx~3i{Dq{l{ZEfnZOd?a4p=?V zF5Va!!FzQNin34t1Rmm?J^M3E;QA^@XDG}UqKSUENn#x<>Nm8=C>a&w6*Fx5Dtu;U zxTG7f_u^(|gh=QF319o+tnr;Q(SAP)RS(;oPdYpl%JUJ^%gnJ4aw^_n&5vSpPSXU^ zwn9x{Y`YPrsvYGbv99-J1`lr`r*{rLI5M0QxLRctdaNM!c{luQrWS=s)n(?{Cst3u z?X;aocu2HSO}2Mv>yTGUbEoc?ncHQI`WF^q;t!pL%kFi);{{|wsX(9S@p49(V(7=Y ztc`P?i~gZQ0!P+~A|bkFvVxH+8xBSWov5WRpv87RU?33|a){hN@sqwIJ@xYkuW;*+ zWwX0AQQGg?z&7GDdt30-c8u|mIQz@zDJVTq=JQ*xcbyj7W79e=%XE{C0r<P`RCz5Wi=!1t`0$0~#YEEKnYBc^Y zCnT|MTI^jNCfFSIV^@ ztbfH=Wq{Ki#06W>JCWAdTo78?^l<=(j3S+hhkP%EQ;1{+HO!OCL1qyBnHkQihS$7R z+B2*y6bP2=B@pbtLBx7UT+GnjcTkQ`*7hb{^4rMcY)vfL1NSUZx}DOiT8bMij!axK zrKA^ym{uxw@tUx4h;?*=)^v*fw&}mKp41|Wn=)6}saS=W+q|W~aWz<}N>5&Em&MD{ z4AsTPd!>dUfSm;t#f-(n%BL+;ZR%u&BXXW`%5D6%!wjqxcoz>pFI3vktMKY5%(q^! z?C}4Eh~P=piUDz*RYeR=wS01|utHR^QKp^D3AtnV`$X(np0{2Q$zDkD*DMiQ%~WEV zt^~FGIH7_}YDju#S&ZyQt#SwKpeI6DK>f+4-UHdHNJH+1vX@>CeN$Ik0s!2lU*f+U zJy*ePN=qWz(Os8u*&`WqZo2O)+{MggmyA+cTB zvo9KZ1_8!()P2~0+JVQsyjb3MfKJGhGQafX*8`J8UMTz@HGhTMeb!cV5#3z(3A!Q@ z!v)M4ppK@bC5sWvPKSYI|9FmOtRl0P-GWy+kE8-*O&IF1)r)XECJ}(@f}2cY?9%_1Rt6LEFvsmz zgKR{3;TB^p)!{P=g}{B>=C<|!yp!uVYN&H>jgDElk1fq7*t#{1LAure>LhQ7n|Vou z=4b`uUfD%K-iviD+g})-oXbcGiHrGj(CmcOrwRQRkVk0a6R5UCN#+g`Z2hnQ9Lr4F zVCqA9Px+R7~-SFH>PnKIt~R-urK0 zEYevxnEzjt{%7@H$o`kF|E=uYZ0vCVcaNR*e<_!p?f-?ji-xE51dXW7cCLc$Fe^|K z3FeUoB6nf9llCqqrUtY^g-%AAT`%ze0)zSj2uE(WrQ7T4|E_+O9aCRkys6fVO)o0X zHRx4!Q3}e{aVXacB z6;qq+wI~z~3#oX0e%?JjUuXNdtCi?lPL$8C1}8OtQ;TlP&RC%(%gkgze0qw`5W;#h zh#JeyfWy5Dt5jXd&n%-oltFw(0XKct#kJb!E?eg2p@<#vG`gUO$3*?}X21~cs~`jg zF7!5i!u2wqX;4mHSQp`T;9!Q_Kf>_f?f68*YbEmjiZ886K0fK*MWkqH?NR)~HLGM9 zpRXjaP_Xc@P|z*5Xvbm`z7*DM8q&y8Hq;MP&`Z;``pAP9ES;!p+6XW*2rO?X3+I}y z1W2x>da*Wmc{ES1(2jHGX?v?!+$rIno)T$Ty<**uqbag1jnk`SU{Te4xO$acTdn!R zd)Gr-SZpoKYcav>07{|5y6IRU34473Pk;#d_7Lbz3JX92*qQ0Y@j*e5!&Cv*S1e$9 zx%3|a*}>N?t;5gY%(#9Miy0Tgq9*{ruwVod<~9klv@tJG2ZV2wvh;Kn*VKyOgE)vnKXRJ4h2n91#tlsgHT02#pzNz`O_Y}i{^<(48 zq3>^!EjovFG%bcppf10MB&BT4P0XK%U8?wgCveEX3NQv-!xcn1@RP!{1MHkd6%m3b z=%x~%@ye6ThPtJlF^&rCMDe|>1UBm#7cn02f8+MFIsGYqRjxcGNF8oqEyU7mEoPmR zqM%J)2k@VPEd7ZS9hj)CT$kA9(ti5k=`8+C4ohT*-q20NM2CBo*EWMTVC^mEgN&yYCGWJ;>gA_VD zkAo^F>(HPEnBzV;Md%Rxyr`?1C7}+pLpXGkTc2B^&2l%0I{jw`OraywA0Tv>Ti%^x zCsODeNe6$h_rUe1o)E&EswTuU972&24l?QL{o$C!gUq7^7hl*T7(S^Ih|(&fxDN!h zIR1|dj|-{Szaiedo{*KeIPgwqiF#vMO&?Nx(T^`a0n~c>i_p26jv0WI$ zAz9MA@pK*LG(JQ{qgU2AB|}NCA`pR6%B8)(**>e?n26rF=nXZsdlAk4872=byqkA} z6dcmG#7l&CvxZ2E9klf9tHc`lFlu9r^ z3&88ci3Fz3D1p!~U#Fr$L9d~Den^7_YzyL6IIl^ed&fR?Ip$AfBLTcGYIJC#VL23x zTK_R`{UiBk5@?N3K8a9V_(Tc7BEbv$m747Eb)XW%;3e7PLPcUdh-v>C<>B@WqcD@e zCMTVzmHx&&6Bb4H#$Lg$340*$=Zu@VPFE)n@b+v zrVz65_qaIGA1oJnDBZz#HU}pQ-Vlfdy`Jv6 znYK}{A*){5w>u{anlnJSjH6evveC1P%I0B(KLSU%2VXW0fOWP~Z1K+9iC5M^h%%#O z!79~U*f{#f25@sbi%4bz^cVw}QRsp4Q6U3nucN}MdB!p-0eu-kOk=Ux3H_~7-kBn> z8^}Up30e**_$nJyx1D;`HKv|?`e`l&zIo-&MbmVKf zshk{usy|VuPJ>9vWa@4m=YO3Z+sf1Me+orJQWELB6X*z@JgSZB(-5$O|4D}&fTX{iR5mFI7rw0P__73bdjb)%JkgkxzB6#256fLc1b!;T3i*}wOB46;XhA2 ze)_vFv@%Zloig@0hl-}gF=EbhAqn>5!3G=ezbaA#t;RMK1`_uTiZw~-~;aV+sGCQy?hk&!!o6peY zzqb) z5XZjHD(b~VH^A7pTRSOGn=2-EUM#ahKG6GgnNs1V?yCv&BK)@bx#KQ|tu=Ok7|iA^ zkRT^YpE(_~Xo|skm2WC?vFLXq{Y|KkrR}#d?qM8S5f?GM@PLgS!L~=fDE*09wzu5sMTb zOxY9JNSC5t6TN${z;wuSzubdcC&ROFOnR54A8zS~fYsy-_&>44!O@K3khup{nAVwJ zfP1jwDX)=gHEJjkPRj-dNWwt&vaFoQ2qep@?W7h@du-2EbWbsS0^c;jl;-XCoF6SUfC+j}<~qdz3pQTS}Y(o5(f} z7PAG5fbq>|?+pgHJlq{3s=1+2rys82kOv&?;p{WP%p6D+u9^t0_MoaW1@ycn z!{hqzNS9Q-@y*%< z9LNwpI+Oi{+pDaOlw9B&PFU(9J`3FcVKF`7Gpsscy@u%rKK*CwiYz&q`Tx^3*jII|~slfjniNYmt2 zEF!U}DMfK9D;}OD5T_abA`!jrR&tecl`@J#@!BR5NlGf+F_KcUbJDErsf73$*zcGP z27NbYz|_;QQ+<3(2*MfIi2^3$@!`<^JvX{UM*;oMJnw%VeuY! zsAbbplsk&th~!6+N_y*n=qRw8K|iNkk66X79VGM=5sGP9w{T2G(`Ft4j_tQo-6!1E zj_L;$>_Sn%UXssd&aXw^J;GXJ#9uMeM9F+9{L60&O+#}-QAAS^0=;-Br5UN7t18A> z;fcniCj2Wov58X5UsNg_>+OCrwzVdj78fWM;=_woYyYsDd+#j(6!1hRaM6HxNz~?Z z(xYhWW8-*o`@MsXt)R<>2iqc1bF#(yX+Nwr4#Fx{QdG~@o+o~(+3@QRz{T}~)B=q@ z52XhPSxsBNoyb&rt#nX{7zu~&Uk^hv@un-#8stEMnzhXRkDyhGCp+>vV2#Ss7eEzVSmDwe4j`d2F{Bkk{QhM(cQR~cLepkVfN zhcT_5+bz|Ac-bzGu=yq0j5@iQ@1^He3JB{#^Zl9=Fo!{ef@y1Kl}aL&A< z21_=SFb2y@aoNVKS(4nX&Otg;R#0c#RbbsiMAgH=2$i7!&ZT4oBXiW!zg z*7)Dpq7|gcM+N>Cg+~Vq*A18=-$4}9diHvX#xc3A!IGF9*UQZaJgXn-3N_>T1afX; z4LO<>pAbHJNFKVTU{rjQ*#4Y3GBb#eRWB(O-*wrp*A6e2nJi}z?tM44(i!AT*U&Z z5A`X%#y3B}VZiu;(AC8wt`zd2PGC#nOh)QM7@vN@c%Y!j&I*Rj;ms;z}9e_|C95CLp_%$NR)w{~DhmrxPb{ z3>4oz0Q^A@cqGoQ@x-eQ5QhzQJ&XUjRyVY(ex1<8jkWVMOGDT6IqBwBlS!uQpojNz zSfHPfL(fM+_D<2iMT$@1qUdX!zJ`6*I?P{VPHUFG3nSr~tg6boju&#HT9FwafXtVI zv{N4@L6-)PJ2|MKwe`&gonkVAAJLZ(=28#n%+O4K-TA^aEqF%6LzNWMJs z^w~)ru8%B;PxYX#f*YVd;>?X7+#+&mBc#G@Bg7}uQ|+ zuhO`wJCQRcZP~IK-ZWUim*OQ;09-T8FgD$6);TeT5onTE>o`4BJqfhF;X@suf7hm1 z|0rIn?*Qf!VrCF4HM#_+`}sjk7CkTjzp}Rf3DN!=wsG+Au>5~v8z;;E3fnmUo4@@( z^pu>(5lEwIU+_3zDaHEzi`iyC^4cR*etzhPjwcy_{f+#4pF#*E6d(>nwYs_exX)PK zTD{zQb60%axY#19RBB5)ds8(uG}Qdhxc5$^`jOZqeBaHi{A6@pBs&Xm)8*_|7vz0& z!E||>+&YiQd_4c^5XkWL=y-mh8ON7N)Joc~$ue>`#4c~Tq_W7=(9BdE6Qg!#!!T&e6>^$es@32isuX8P+8kBs8rWaOSZNEt!9S146RMBi}~5>`Mg>7z<9gnsbO_r4Z(E!{#uY zk*G`HKXaR>4sJ8aVj?vRWDkPm-K+eIJ)I^3$LgXY#av6sot7DbO9T?O<>YKr%A6O{ z^h(6EO&AfB9unn3cZU4?R50jhr22*<_A5f>{??rTp9{Hy3$Esf%&bdp2J*CC zD6on1qC+%KXehX&dCdd=8DL}~Q^TpqlqM|9ejX6A9qdmQWGVI;k%d5~z%0W!%e*kv_ODR~MDajUj%4ku@s3CSaZ zaNYok1)t^g^D%(XC(ENlPM>gQbGzgmnROtteLwk*HXV(`Bj(42C#@-nK?F{u_T0nM zz)E*!0p--v=>}I{gleqMdlr)M${}+8AF+xvqpQC`2}uAp4m^QLUZ0tL9+?0s&KZ29 zz>Geis##(LeE*(l^Md!OTt+^OGTa+HZDdpK{s*AP z0!$>p^=j@P02a*1mTNFDV{CnlsIzzyE~#V8(o%btyniP&$Ast(37|3a`jf$1foT@= zJkpvq(F#ihYeue^GvIS5zh}d4$n6EF1(hgyB#dI%BDowi$7?=!~ypl?@Yy?{2_k2#6+nRKR=@U7aLx z^tek2?B5UOACo!ZQ45@#GuaD?Pv=^mD0HY!St6f9$xD+_wffJmB7pnFQ)~UV1S2bC zfWM~zHB|Te`h|SrC|l&oZ>8P*zBg72`-}ic>(Q$UHd`G_DdFZ}?GnD{kjCi`voN_4 zyMhv|2(@!a7`ymrWq$=v8ISILWLqpEcopDGg~3@+%kgD67Oc9>q>AYcct0oxOo=tG ze8N1L5#|Jwg}nCk=elnDz-?TR-OoH4aW(57Z0vCh`W*m-WIvG=aOUY&=qXap-mdkK zaG;Xg?qp_Mw24ShiX6r*NEH%__(F*9+}1QML)g-K_UL+}?^Hrcq}`#p;IN^;hMzJmD;T%DBR1@! zHYh`xQSx)*?-zSQ`Sn#U-{{<&Gd%O3zkLSS=VlRX&J@jK_nu(F^&~|pcT&w6fOEy7 zQTdb=iokA038J(eFf~IXHI$K5KpE;c#w5&8BISTDX&=$VPchNRAd%P!W||ZE*=Uk* z$QgK&f3FP1)3h?FyWo0(go*zMR`OY4W7y(;G43hoDxsXfI6;n@unm1vLVgAYbz$y8 zB5|**gA&y(%L_3ts+3CGWU}Cs>$!g-|03^$uZ16}2QLkZ1;y0$L)0CLy|1>5vt9H? zD~C<}q{zJ87H@t!7Pmp3n&TFy47B6_qD*Y98_*Cr>5dW!811bCgYCry4!p+weyXeb zR2bl8drCR%46=|uEW*p7noQ{(#esA&9Qw&-!hyXPgIJbKno-_~0hQ$I=WO0>C%S`R zCuEF20i*Y6QwqyI9XW+>Z8TipE0w-*5+)n<^T0fh^O~5Ar+E*7M{+S|Ve=SnW;w={{F#E#=V4>nR}fFn+3eGzpOcYLlRp%r3^GeOrK5cpo3WI>17 zT8li$rX{p>8hiX;T}+N(fYwXWd34Qyh?f9Q@|2GX(=O| z5RVO#g#uDI%RvL!i}|1Hc=$5{Qf!oTmBJa?Ef!iRK-xSlY&rl|;_Bx)aV_1Q^O-f$ zV9xJi`z%g;Vq2t6{dzEjJ3~PJU%BuHYkrgs&B!ofg0zleCj}}Fd)K3Unk`$-X0Bz~ z+%yM~`=5)o6r+twvk1&qrbN-njlq*F3Q2V8TtqgQBOw&6DQrNdNCsmJrcM*d#w-&s z9H`2^#0~1TeEZ^tJIA{oU$8;FkAFi9D`1uogpO$W@Nb3%JR>KNL%>iWkqUjcZ~z)e zuo>IRbT1YQk?Q_y}cC6R~FLII;6j8*{}q z3nJsM+b3dFtYgVBluKuM1N>`s?4Go|XR7U*c_q?pkK^akZQ~0Yiy&ehkWqCCd$JjR z7MBX%p4dfKzEg~0jTnouzSfsDlP$+7F6NQ8mD_S*a14uL;|8k z3%Lpmn^IZ~<$^OCJmBImu}YDkd#s`SVu1(EPqU0`jANP*yW=JRvFmA6La>w=HY^Pj z1d*v~9t}h!J%g61H&7bJ`lGk7x$&!Z7vR36FrA>q@vAyY#lGucKd3l&FXr$w3>U!&ySxdB=1+o~Q|Wv>r1S%)J{%F>x$|2#Z@ zED9M}Y~|OERgm|J+a9HJsBa-I3|*bEoMdjkHt5Oq^1~mRwpF#-X=~Yb{iJUS*Gegu4D5ZE*Ymzg&j=gGl@rLTLZUsP8vF{l%4H`H{=`J>?7{23VK$m&1WrED zx&us?u}lX_X$F{9wT2kPm4{Y1Ma07p!OEYp#GD2PuT0^Zo={NUG$gE{H7!L!{5?VD zAyNb+em(){(GFIH1ExOZZPW%}S(F zWO?uFl4F|SFZobZMUH|x#oMngtcI_ePhQsP!bR!7(h+zl*{O@~F53U0skmuPKfOW> z1>URX^+ew*$aa$xM{Qivj$FqNrpBa|{96SOtL~E3p|P=*vA~G^rj+!c+=k723FMJP z$)$WRkEoi0GQa{GP-Z5{biAdHtOvZcs`A2#n2>c}u6Ith=5a6Jo`9W2@Pwqa)z3 zU2rXa!kVE;#!LL8!tc^|#Z2z_=&-Y3QAyFD%6i=pCk+;}vtL zZGW@Px-1sla1<5|dg2A_t5I3}%|HKo zgPwOdkiIN?@Z?sXOIz+~Er?ygBU($Owg-9y*)I5XllC5o5Gsl>lLFyYp!sRg)okA~ z8Sh&)oq`^2EoNkzZtCsTSQg&%tf0yp(o|zeC70}_VPz(_N($G_N=A~ zz3srS?usR=R#}bIc1~|ki}U3Ypohh|AJ@uR-DCZ`;`_aEZpfi8n@@XMqFFy8hug^c!R`u^C)Sko^lKhE z#QoF6yA#BP3j$u~ABW;-C4#wy3btMxc^~x8VxA9Xp35RiTu#8;*8-@%NW+P?^K01; z>B02CWQD)t3$y}=M5?~?0q^GQ8g0;Q)6t3w;}A#126v%`S3J@&J9`170oT)qGimRG zYsmv&>bwu_I#S?V4-wG6TSxCH7$a}Mp_su=ptJ|!<(7~#D_ul0z9^eE9oEvHC?(a7 zv-|~kaz5`UavJAcj?&_mCZc8Me94L7+bN01`4sPpehM_}EH(YLgzTw^3M8|kJo&L> zyNT|V*%a?4evB=yt5!UORgsUsKEHJZ1!s$AQN-O|VrRc3uHB^F)*|Rsk1yk@o+9c9 zuDm*^lDkkwOE0Xjt%I=0m|E8$T*}>)-?r9SGchmKD>^(K9(Re^528duoEq5Z{;wPDE1VVBiwmGPqJ$8}$@s3uFbe$1Be47#6EKY4aqRIjh#wu+@4N&p~# z(#5Bw7blF5uWy;(%>kK`p-rFz-ohv%;Wr2PxOI^s@_1QLdmxv9PKN6;*rC^8Bo3-R z2wm{tBu8Fbkxy73p_cI}>)ZvUer)rr{379GB$WH8iOL-cCn#x6&;*&!O27?-9rTfe zYx|l9)e|^A(OtP*TZ{)9{7poW8@=fM(C7 zs9?k-sZYHcLi-zmPU;N|_*W);Kel{x51R>4Ch|8c@lREna#pWk`#Vhymr$@*{Y`(C zFITf<;&FB4UKiV`Wz*2E_tA|#d+WmujFGN@N@Gp!ARs$-|0&!{iEKx6G;Lb`1BmLc zs?ls)jgPmx&v%2Mo;~={Ekuw<27Ue*hP5K zQ8p}GEUL&fqkq1BdC{1G>KO0r4PJ7PJ^3Ob>`Z^8m_QNdP|{fYl;C_ud11xhzW(757cU zq$ot|LSRY+stv3;wYq_h$O(iHNZK>go8gSDq21S482M{8#rmOseU_m^8e3hBg%?35i^UvxrI&j6(S`B9pskQBc$ub)M?2L^yh#+|7`s+rYW zhFInms%59z^aq70tVrkj=-8N^;@q`ee+Zo@NSNRZY}K_5&6AgA;{_bLSfPTb()Etk zAE_V;zg9B9iirr%9?4k^PN31s49Nf+r4??$QK1tvcSE)tHtAodfkKk+j+ccw0NX!{ zNip5EA~Kmahv}U(CfLD%VqUTl_xwSowd7A)3`#ZALP~mX9hVsn=e3Uhk(!1!Ozk#V z8<}k?AUkK{b^UG6mQpm&=_G;xxQLd=vG->IzgN#70*l6ccPw}607bjW^JT5Ke>vnc zgpX7O9%5@`cG>?Br9Ax|6B0+e0h|h`BN~AzozWdH-km0Htl|{7UXr#*oA)J;6gbBm z09&1Rbu)0rpYOGl96^gUsNIwz-R1hm2}wvoTkVFW5Zy(QM>MVPrM0T%)PTm?GIuq| zgmzSYUh?l4;);p};*bZPuHz9~$>P((8KKj_&qmW5o$n% zv@=0=0dnebDS-k6H`K{_PdeCtkb=Cl*C2ybu~R0j>H~4G?!4P^_!Sl6B%K5X0H1Ui zvkw#u7$0P{yvpXG#p%IbR@wEdF;Z#rHnKrp9Lys)NmO@d9Z~F}IImCG zxLpLKC4-TD_W46@$SR0L(zg`eRS(NEwE}-a$xh6@laa^t18_UjZ39kqyc7^thTFk^(Q1QmW;RqaRzEZT01=$ z_G248DFf-v0w1ezviH^(p8FKWpv)u#sXJ%fzOz@r+!O>Zvl!d~hp_g6=wTS(C19>c# z1X`JcIs8EmL)xu96sEhD3%|v##DxN2I7w;AN8l5XZGqoj zJZiWqa5eYPC<3wSQsLj;>Y~e^&cNfNc33Q*ijPFQ>T)@oS^d}dI(o`d+}Lf&VPr|( z_+fpsczg}%vXFsw2?5@z?TPnuY%{y+iTA2P5x#B`YEakRhc4sv*~cN~+7dLvn028M z%vWbopZ8d{vC<=;GLmZOw3K>gMoq#JKbOO&`fB`IY(Ok>>&?A@N7YYpysHOF!lr3) zC>zH%$@2YB5c1HyLKA`FLh8{;bdX;dEbb-}nfBSd<7yrg2bf%Y+|$|K4|NZN#8j8s z#kg z@!(>;Q45$WUt4hjT$(&A?2~ndx^~*Gc~o%nEOQ(X%94^dWb&9mxur#Sob}i;Y;8iM zuXzMX!`x2$o0AM-oDq^N<$18kTf0kV^m*#Akj9crwt00*$0vOcXOy+@HHCP+q zM!kt9JrC1o5u&#dHupgu@_7Z^lfP|vD==s;+hlMxfIf-VKCz%lDIh+o1dIq)1`^@) z0S_&`jT*ImL*2H8*VJ#;q2b?T<$JsDS<0e%>pHfp^SjS2xOX&DRZ)lZ$iF9?PWnG$ zf>Ofq0Yxg*xYe<#Z`B5Hb}*A2o209ny;xqMTKC8o-0?$Rcz?k+vbiw>@Unm9^Eego zpO@Jf;YA$_Bm&S4@C@C2eo}v2VQ;-rlVHFW9KF|WzJL6-rb)5rrd71vuq*fB9qn%n z$*6P1d+C$uIcDwPD1|YIg(|u5z^a={?0*0}~?Gq#}1UJWB+`$m5$ zq{%&JHjU#l?$9|cWeMY(NPr!AJGfMp{zZT0F%)dOJx-=t)(1`#FiJ)d$fYYpWYPwW zL=t%7*mrmQl}Es%Q*em=5p;TUL=(TJK4!**zm&DgHJvG$ah7*~Jhh7Ri;6I#om_~% z$hbV0!U0|WyqZa5SD&N>8>aNz;2H0D0Hexk+VBrAT%3dY@agx4-fS_pmAq5a0c$$; znX~~XCUz|%)98dWC97A=#;A*4#8SSyna^o8TxcG(%tExs)|YX_c#KAQ`A~}7S;o7B zia9NjjYfo*f?EuGX}TkQ(8oZFx8PN~6R~?u)B zg5OCtAXdeFB2biH17~%ZM^uv=TIX)P<0iZ0jZYI1jj;tNL<#XS(8oo#fFl_TyfYqb)JVJq$++*j zULqW6-dg?vIx4>yl5-prBgnp+JnnBr0YUL%V5)H*<(Pfz7ccCf1#(}LsXzu}d*)Bu zH9tn;_cJIjtzWiT>y2@6l8)88wn7l5OhjVxUg83gB0mGg1ZJVX_C&S|$#a3X?35v19 zU`1?tT9WWdpebjZAuyMZkIQnZh)BXX5&TP|p2vA1uA>n{70K@3S0lr$_Ds(K^c;X< zj5KQePuWfDIA&~|C@Mhp;d=E0rFCOUtfc9j!MAzG623m&4Bsql_T4cwVZ#!0f5oqcrrO;a31)* zN>V!Orgm>wUz%)sH`F`!2KXijS^n>`#(&Bc|I?S}{J{UeWsUzvJ@EV=Sr0Z9Bz(Au zG7|fWxDqlslarOoDtVnseVKQOd_bFD_Yk7;9{9iTGC!oGkPssG0;F}z;)gCB zU0xS-GF=R`v^?%tiU(`zN5VAJ_H;BVM*n247s4TPSv%8 zKScv4Xs+1qAH68Y)a5bBy;Zc&q92t0yK=ZB?p8L~-KtpK4;m^RFTNDLV@(>hYf)>P zL+8;ca8Y|8Z{FTxrjam%%w#G~8LGQrXC#?%%y$@XP`<%W5RY0mKKOvRJr9!zUxC|ONn|5%EsME5e;B};JsCNfRxAFwWk8VIf7u=$!J37h z27=l7SzD5u?T$ zugMF5Uk{KVfUWQ8?_|7@=NKPLh6e*9W(RsP3BW$EwM^rI>D~_)Vo4_h(m`mQ{Wo^W z!djpZLmJ49T`FtAa=za`6pGECOO*T&#L=;;dT=2sMlyuY5gzVWFqj6`^<6}xsvu>0Dygh!^A@lE+s+0!7=3}|3V{E3dfzehR7y=8!bhL<&TlLaa- zA=HVppxd|W;8XeZ(G5l!@o#xRL+C)&!X#QGNkLs>;jk%K2Hk;;w;-@905V*VD!q%> z)21>T(lR2_-XzE^_o2hmO-}N%Qr*p+PMD#z!G<{aWxG%!dOzO5#6p#iLv0B0VKx=d ztXV>5L9w4nHB{y{vvr1BInkJft>9OB!wNA&bzI^BXK+$xgW_IWD|fpvZ906*ZG$oS zb+ZMRbP}`oXW}z89_xujB70CYQg+h4zAXp>HYXB;Q#^0vZ-V(TZNUX57;!ILk4Sfc z?Z^CQy5K+i1z*eRrgxk?qe4Vrn9KO~Wp^03{2P&PLPv~SRVm|5aKl4*xJALXnX^y@(G`hh(Fhp!Y ztuNA)z`x5;Q}ar02%1)1gMKqu8e7-iz8w#7_!it~3wl2`#0nbC898IwcF+-91p8uj`?qLQ340i&&~ZM)GC+Q9mysX2UfS*9yww)lxjV zY)ZAh+g(=V?y>jK+-)p<-U|?GpD{H@5QcfcJJeCcgqc!5L6uX(c>wf6dk7&}^kj&7*AHZ&OpI+L^_j}u$>zpajNVxY+DoE;8 z$oD5FH_8o#cc=9*zPPw6FdimxsF92MzPdA|JH zK+e*b-*C~e;etVw;G?F^*HAT#$S`axj&#(dBkREKLa|@y{Fv&9FbE&atF!A~XJv?d z8}Y)C3d|b6Gc??!yTf8${SID8ZwVj5q6n;r`uBrArb~BDF<+xf_h<+P5r2Et?VO+M zIVUVihaagc2Nr2iMb|ZRU#bblk(2V%P<8_iQQUlT*=ajB5ff3%08pc;hbkGFV=uA9 zlYao}B_#&^>Y9WGCme9#2LRA^*e7Hn155y_$yy@@n*e0cIU|LD5!-0sE-xyAfDR>~ z1unL4;=HtbGs#7#R>x-E_~CXr1n?UH+q4e{xhCdg8J8WI#wSh4d)xiyw@M@F53-a82%|Ql0?J^Y~J$T6K{~IK+Vp2o39we@c zxn9s1jW`VvQvu5$k3SiSyXoibuOY4bE@FXeGep~p550)W%SX0#es~!%zo{$dMk6Bi zpC}+q?bUje4kKk^^DP&cQN7205YUsHG?6otEg)>iOYBX%7uOGcu3&6- zxuHV;hLx=m)AcUoCUt!=JZsmQCKm0XWpr)cq-SI$c*Mb!t%3mm1S{>t8`QnV0Vx?u z4Y*&?#=pLJ%;niuyXroT1gRP8v(YA7?=1HG6M(Es&#ITbX}O*%Mqlq&6F8M&SZLC% zbej}X8F>Hkh4r>s`b$=#(`j1*vHK%Iu6!u=lXBhB*_9wydD~u~nuJ{kVa+3-o@eJq zVDu~423(4o^cG^PLI;wd-PqBGiB2OcSX(Out5(~i`L{seW*G!&{}#p8#X^69ZNtXo zYL}B0`A=G`6*63Aa#4}@&ZU!NBhy|HP)VMVBU>f75VElIil~WiGzMvm{m}Z1Ja@luo&YxH?XrXT%>vDc7e*e(uIhNL&ZOew|KK z>p#ms_upAGBVKT50wZOdBr&%elvK_YEY@>27R4Gh0QvvtG#24Iq?M;|4i=zCEZuD|ArifR_K{P`Q)^rg{$^a*iQZln3@hdXteJh`Ij z>yW}<0uYlnc2@LH_UdZ+u8mRdB=deNt(Az~-Ynxk9N#AoEuPCEZO8kQszXcc6TyeS z{`}zA*hbO%j5M+kiAQ=)h|wk0sA&tgFV^*dl1Pgdflnu&zOvTEp>SNZROZd|hN!si zwb>7!m)4YLt73R>=C}$A={E{SMoJM&5PYoKrAKQUG?}3SE;63_BdW7rk8pIk!78FP z1~@+>9CBKb_V-rg1{XCkeVE&D+9=`po1x?>!!jCGQ9E?SC_0OQcjULSyE@PtQJvGi zl&uBlU=7+}Q!}u^t!K+I+TxikFsRHjksBD~+}J}5y!>VekSQ7jL*Qy)tF{a|&ILx* zRCkJ_I9?Wayg2~unpWh4|D?9G`NxO;@`=DkG)rr;r4xfbN9v&m>ogq*yd?;VLx;Jb znNO;dXyf0|9P@;{X_%6vfxH1gEdZEsMSmcLgvPn2KEAyUNY&I*se11I1H#@1#%Nh@ zZ`GDc@)en?Il(SZ$of}VbmSS3*1?zYmmO{N8i_r;xzdADtKe6k=Q> zLzJV9Pk+-scHbhSd;5+Xf1KM1^le-5 zE@CbSRdw-4*UF#AK0#cHjYSSmox@_x;Ep{dUt*z$WpBqP|Ms+XnrE3A%$7nq?C*BB zeLu<@j%hb@4AFO;QsMpOaooa?vSLRYR;l~?!QUGSW2h}ngxFFzT*V>=}2TASO3f}t#KQI^W ze=*+*#yLG;uvG!yBN|?$Z*~qb1N*qdQ7~=7J~Hj}!cJ!cG)u=B<8Ph;qdflGPX2y* zA<4YIUi8gpN{l^SI|n!30C{2ma3_2@f01(>vKXl)XEv7YXdmF8H2tK6kgI01T@S{o zf5OKtn70!Ns!ZjHX3pGo#H-U?*>j@eBc$V!-@pMCTnOwaGllUYxDiti<|}`5YJKXqdqiU`Za=J0I15fc2IIUkP|7$4 zCl)N-Ex{EkB+&yxb?B(u+(V?14qRyG;FFR;i^=Mdy`I17<*I>w-baJOAxKrD00gyH z*6n2Ta|mnESMMTuP)d6_+aC-kmLl8yDoXS6>IZGRA4P{rxWw(uP|H$@o;V$3czm~- zKPV>*r2Ex$Cil2vod6=nLs>HV>6nf@`*XD{UJofG;tsWL>pB2)*my7!2xxtrw@t zu$Mz}Nvjj-5io}0XTkDs;?t z6ZaNrr6OA%DWw#K0gFsj$HSTlqHyi1x8_fV&7Zz3XT3Fk@^uS(l~wF;3>sa@iYhwz z)AH%d3gr%(>FM~{a#qkZF_2y)FZiCP?sFy7x9O8_mdp#W6wLjMXknIb%coC2KaxIy zZ{#RGLdw>~D^JnC_nzOKjvKCIu`@I`I^9r8G0}fC3WE^5{_@zOK8$#izwg`Uv3!j< zQcckL6Rln1k)!j0k?{doxYcvjFii-gf;G9gnvc7_f5A`nT07v(`bvJ~QcnU27>xm; z_>ZBLBO8w=FvSg!L(wcu)?pxAFtd%}QkK-JGg zOIs~GoejG4gZERzW)yEMSSo^&IEN)GUsp8>FBNPS#g9r$;sk+4V=+}Xx|OQL@|?>D zcJky?0tJgtXa=cWN&>S?Gri<_PuE24_uWQkV!!*uKk*Cbu$j7ByoSGG?6``JsyhBj z6|Pi6pF4)ZIAr;KP!Yr_G`52K_BRiJ(k5?XbX|bL|4f-=zUer|ST7CGaNwaYx9(<@ zY2~3;k86xNiAhe5$EO!_#Mmb5qRMHZlr#i_5naWK$A@#~>?Ck`Jm?#48Wst3xl%NI zTdo%u$DXoAOREt;5|9)YXyJG>C#f0jHgA@GR%nN4{|pJW%J#$@D}O8RxWNQ06Giq! zU<7ovhzsCcZs#P%TE+$6NbnLBU&oC!)?d`M4_6YD8gXv-J>60#60CeSZ20o$4ZOFN zM)luiivN$*!To{nf5!)S{{!auPwnFWCsOiq{omXdNB=2PXm#ft*udB@P)I^(85r_b z2IsGo-0^rY58)~FL(qSrM^8%hveNv=d_i7wv~YE`@TV>FWYw~+xjB}nKI-JkXMW7w z-OTJ^v*Gpa_;B-~_bNrF9`!BLU}Uwe_2+p{YRU(lucK_DtphdXM~6e@?P)yjv-R#D ztPX`r4i|Q2dSC3?+#fEaG7`$_G~Pyb;PLM|sx7K@40baN_`JVOsGGRh@)~+OO{kkH z3VU5$+IBOypss22%+J>5*~Jr=3=Rved37ti7XNxE3CrhXE-iXC?!WakV1xB?F~8CH znwtNW&)a53U8g4HJgnrVE|2kdjf4gLm=1#YkM0gO{B=i4ZOK?C#_cG7 zZhIf?cM1i8NQaJ*h_jatuOF@d709rSX#>;^rpR1P5_YjxGurv6YH_$!@p0IxMSv3R zx1b}kiwPSICv)xPiAH}mZ~hH=s(u~V>xi86-NV0|Z;iAgofcU!kk50jVS|%>d*_6Q zn&{-YZ{ED2@4~4z>i@}uL&$A<&5)Z%$J~aCgixB$D6Q)pz{c^Msy1Va2?LrJBcJ^z zzhshMP~B8i?O~4ZO+w5uzSOd2&nYRaCF`t+u!j%!dk_$Ja&n{L5GBwDtgoxnc9D(V z&sv_>^ALeX5QPKdv;dCdF`G^zsU$U*7LEX;Kqh6RlHlF!WnR%2Nqf!C&wdslMWgq} zhN9{uJIzphv0E3Y?;j}DEmGyt6G8w5LLx=Ka=X05;O6;{Lg>Mx-ddr|mDUg%l3Bsq zNdHzbB9H`t3skxXLo-iePh!+T5=n7BTpIx6o`#icg{hNTS~Qdw%woxcMN7Wf2*R+< zBFd9kBC&$!u%FbUH4Oo15ZCe)?)f~C4iIO^|D=S^eAiU#38R-tO?ZJQ{9s6R4M01+ zR~%8jpOTAZZv{7~vZ)NN@U;B5rIQ-^&l>@`hOBX6*nYK9+yOHRus{ZoqnsFP8oor) zrgUaoD7qQI7AZiT?MYeij5u>Gyihw~a;1csNaADTe&6T3-OAMb7mnX_BS>DW7oY*W zpfHF@FJE?k4S?w`7&lA6-js=$vM=4nw(8PbC_PZ=$842h;BZAhoU`F6(Y4L>J*mLF z0{%ekVKL4=1kv?K!tT;<<-nD@DnY;p{*ivu7~2ztqpJb1VscAo^0AdKrQT5nB*EFK zrij`Y`vU^XU9LcBy;{3&c8Qh9h8-;^wZ-K-X%t36jwXh~J}ApEfd6XNSd)as)P?R_ zfYL=|58GR~r-CX+Yqu-$n*(59pp9FMk|Kv+o~w>CZ);G|EKiAW1;;fBBb3oge6_3h zS|6b4oMVkQTES%U&^;s5N5u8<@{Y~CqkZ71d$cCckZ$`&??K;XQ<* zcBk3$qIJ)WV5OC_o%%Lnes{(A{uZnFXCU9a`ruFX0ekg<-Sj!vf-_?pnM!v@w4zq^ z;6T0tZyS3WnHraW#yteIxi?MJ<^Rf-_A2K0NRNbYK4Vyv?>mr>`$pXG@;em^iZ-t~ zj#>KjjfLn{mG?!3*IS{hcVb2mr;y|jLJhLG=jGYLw(NVON&nyxk@&~qYbvMS{0C&l zWjupDFx^fh;GQ4m1y+g{Pz2!h!I78$ver7g{n_lWtIss`Qk3! z0=7RRR>Vij8&mAs1;nTP0Op)yMe5R5ec&(ggp7m}t#zq0bI5+XuhNp=3 zg->zzNMJ)w1g_8w*f3bku=z(SHm!u=$e94nZqN->fk0n>J{+0z3l=*6g2@c<(50&Xww_l}BG+~03`;#buyHO+;~ z3b|Y64KOssk%52|{StFxCdDd^((p!@CJNE{liOL#K?56k+8882r-@>3F_lA?8yrLy?I-9%mi=1ScX5#4+Im;AbV@8Eb0a;1Gb#cQ#Q_$cS2fR@0xeqB7oIDFFPa z?#!7oO4WTR{yho7o^0U3qEc1veBIxewk5d)3D#afU@51y!F?euqb-C#ZHb9_*nm`y z>BQ%A>D(Kmb?_9liO`oJgqVXgIu5iL5jwaflA5oQluuE8a_PA3tN`A2V3GN!v)RfTsQfk5VLsGC;6HBodUt zbKFn1%CQg`M@+O6BrYx1HQ_P~D4NBcE`Rwe;M=Jkq{(y4xV7u*(qw2HVIS-DAVvtw zA~udWJr1Nem8IZMAyfXYZsu+!S0t>Y`aRbWD?7NMEM+PZ!TBpo^{vNK-v=j%2f2HL z!pD64qlD)2y0A?j%F|nc-&tI47$G)JXj&?CU5{N_ld2(_q~wDY5Q24e=>j25aY?z~ z4n6-e$nDF4u^SKoaaWbCeI@X#J9A?dn7d}E??HV?AYfGQy*>*oHhOFUmSkdPP2g8NmK%~- zH9kcMMB3K(J@qwDa@oYEIq-L3>tmH#Bz9s0?&*?MIwr=@h4!f5P1M^+&M+}0Tjo;= z7$Q!rVR}myeM$sNyE<)!or{*|OIAVKe#~xiAc>_f>_+LDm-JL0Nh}q=^zKhHvx0df zMAg7?d0d8tV(=~?#*8I>44%YZdnN;CCNc_DC=vkg(+*a2vmzw4nvWXJ872fztOpRk zeofPKyuTFs?t#)O{v5Uz&&EdK)0EE5c1|ixZC?zlU*?5VOtc=_KFzye~|WMvXUG z2TYZ4LgM4!GQnj+G}kY_R@L!7&$X`CATXY}X~Ck29&lG1MHkZr+sX@?@oZI{mMQm4 z*OLa$_SaFx{UD@wggae{XB-2ZQ*g}A315%ntbe_0V$h-ADTb(LpZJsb8DsEU6=u~3KQ|1tm0zV{?W!Lp?|OPN7%&M>2KM~hJ7)!! z6kkad_ANsrQ=JC8K0fi&$}@cvV*VHkf4VKIaCp)d;Lc`_f+p|qLz3qlmbpk?{{ftI zhMRG?N$m3#&qnk5<1+6WGJ;g6S5wkLvc$qZNi1TRg;40MreV{O%D29u31WXNEejY1 zOS=IY?K-tS31vuH%UZ0W2&-4=X_>R*4!2r6wyT8YPhnP91_*iaeG87M;{u- zMX+qp_Ocs9*dIHh%mx%Cp6iv!7*czQ%*>(b75zFMJ}SIO3Se1`AuMBTR~kWZB`QpQ zZSY`9!!?U{#lY>|diJv9c3pw?eShI*4p$LIE9q%b(-$E(k(Pc!N^W)FFw`b$=o@UL zAK`c6NL6xv;ZRmP1vdM zcQXT3J0}I$5zJ>5pH-P5BJ&-25Tw3TBjoo0F0{wbK1_A=kKrc6-IRNFWoU+pQ>vOG zjb0?uW!Vj;Fe7zW!>Kp0^WY51pE~S+Q^SRi5SiidSyE!JUJVs%moxGf!(Y{9bWM?n z+={iH<>WV;(#Hb(3fuT|%DnmX>v+uLPskxhv$LUen5=|qvzu^R_mCoX_uq!AS}}7u z%xP3MOl&*;PSuiYTELGYiw2RE-(BM6$;~CHG)>1Ao;RN#L7?F4i#ms`L}Ieo`M zK=CcojyQ#={|q1xSgF~{{+8Rgu03Gxm(+}iE7s~$+^U`>p`;ox;vPaIqMHeSrDE!o z{l^}bv?*J56eexnu6o0C$%0LJCL2|T&A%JyaK2O_rI|8|ScXJ4!f!LBp&v#R8^C3O z1LI)Q=SRDza00)T4fnB*`W43&n40X_-Izw7GF=xx$|c9TeotbQV-#il2W`jSy-Glp z@vIri1^nYen61o^8gWKO;9^toj=Ak#2@}|yRk}`Lbm~Uq1aIiDV1eEsVNSCWbpe-e zqhK~>XY{#s`J&zWV~3ynxgO;n9|!p0@ELBm%PQOl%(dN{e}$Yphxr_h&+$e&Y&u6> z?`^yiD5{7+X1480AVlF@93|v2mUVQK*1N?yw@a(afjHhOCQU=AR_($;d-stsT8-qy z5e5w1Q;r4ucblG5;cr?Sx$(2c3!TMF+<2|VrSoCPK#m+9k5XsiZR$CK={;z$Dxc%+ z@C~Uc0~pZe6ByUd!Nx%UT@GSxwe(o<`X$xVvU6MJr22+`R1H>>6v`LuTh5;k9+ngg z^x_12{W?6&g6(cQ&-_O?x_u927AGYb@&)^fq-vk%gVy=GssWaOJ9d6hWof+iB~5x} zL2*?ynmV9;uFG_>z3#&v{ot7D8Oserk(*EKvwe}M;S&X{a#GDA;m}G?B9b-557+cPTZbEXq)JmVQWN&^;OACX-gXuhxL43Y9UTqYpM2jqsA_p z_}ubgsezY`d`w(U8{6CxX#|@d@|sqbopVL)ebxqMX2O)M8Uocerty!lY&{*yPtJHHulREaaT0dG>~c z8;?md`9$-9b4d!K4F*&TaD{Tx06~__HZtvK$IXNj~T7SUR=vW~x1v;tmeJ5t`T=e+I&S zwmvKf^cU{)1!vfpkUk{XCG?22_^VN`d|sW2Tm-m$kKdH(OE}MA3911U+lrXeN1x{k zoq#o36c8v7Q@?ookn$C-Rc9ncee?(?17RGDv5r5UKEilYR5s<}E%^8sRt_G!S5vAq zyNviM8s4oHs6~%PmA;n_r=KzcuP^MnjSIYMC?YGCLnl`rufTDRduKR6^>D7?t)w8# z*-#s#$7m^GZHFX(8dyXmk3aq*P-qmxJ{j!G=q3#Gl@iu_ApskJ|D{&16!$F~dW3V$ z7lr^06zlj&%w&8iLFS(#77Y;;61R2LcphWi_e5%5N+^Q_32HGM+n_&CXAn?k*b&L< z@zdXhi5|?KX$vuZ7@7v!X!axU!-{np30j@Lf4D+rT$H5(7<`{sGI}nAF{XLytYKH- zBXiP|vfs?@_joDu5K=c4^0ir;G0)+Mj!mRtoC?DNq5<;vGY2ccH$pg%z14x~fWtdB ztIZ>pLts%S2GApu>8b}Pb5rDq?VJFsd!Plu?o96rHKLjyKPgWIKl2P^xc@ksD;2&} zMTpJ<90JeWm9T!!P1+G1Y`VwRN3|OnWGai~Lx~OCkbVx!zYnc>b;9SMc&twcCHdZ@ zTx69d?Me8UAoipcF=(|9Yd17B3J>OlJG#f)d?7)Ps{-M)6nG9LqhX~9 z>GW9OE+*%|`c~+3&^ukNJZ6@SRxQ9(*xMt_@9I1OtiuEk!s5;(5r>22R5HXJhw*C; z*bD!ezP@Aa{ShPc@$!`8r{l786Q9v&=N=9u_)RG1Go3@GN9pg&X?X|U8$@}Kn6FPh zROCyBi0Q`W!@3{(ir=l9*+wT@`xj5o+M4x1XFpu`QR1IfM2}7SEcH~r9{kaPS7gVV!siuGw_ok#onL9;ZI>6^=3me>`c)QdW~7Dxk}y*=2ebG?1OuYAXBdo!I@nbdm)w1OFv9sGcIZ{RCjNI z$O^A=ew=x##5Maf&79O!zsgRaF}UPh9(%{g>IFNxTd>r+bYO=(HSD9Lz{90}G9i*> z<8luP`_C zLW*5~;?$H=w9tZdQi4gqW}C4YWZGT~+%HiP#C}LtFFI7c*B4Oe9a2}6ray?4YS3j; z5K5SDB7FSJuFlvqFvxNl7CgaGqDI|k`Zh`|u-~|G zXX6f-n7Rs<5oEORMsB$C`&=tm-@hC4Cu<2FYQMFmUR$;#0erO#gBB$;9Lc8Xt#(-y zg}c8v_??P;EnwJpf@v)DhqN1v<09OG7uma6$D;lrjPD}A^jP)6dAGE#npA|y5`XDM zM?v6r1Fb@KzjDMZbfK7CKI)q;;xrssh9{DaJ2Hp5lQ< z%*hDOXc$0U?Jx0-`p<)^qK}vv13Adt>z9uf;=b$^-vsV?f&)j!sN?ptN%_V^%h=B$ z9LQdLJm#zP^xCNB6sHgshH@YkBrx5qXLixwJ5ck>{;bb4#I=?t8hucaVM|ALY!sY$ zB&L3$d*J5~@XP;(G0@Km5{irb8|b+wg+BXR^&MlWz30#2!BjX3?6OrI&-7*yORFwk zF^Hw^5MjsY`bPE>`mZGkz!xRo#crPgKYq1%0>sQXQ|yw(Ib*uvu&=vX;aETHoaK{_po@*5D5cp276Y&%@a0K`5?9F%1HH-Pw>iA!BHGKAI zz@K33xJn}lWDPXjR}0X>G{sd(6wcOu`~B$L35I1kqTh^$Ej6Ro9|I0w-8NT1@-Dw1 zpQJ(Z^7MY z7Yxy}c9P|IIMH(v;JGcIdxa%}s5?Hi6`p>5G4w9N77~^h?mX`B5rG3P9E7jhT7cy( zqMywF``JJ*&_^7dVs6T(r`jTc%jj+4B*5FIyMn3#ao>A!q%IRw5b-uE} zmKsLNJDifJs4i*3PpK_-dsLyQFPdA{<+y05v;XucnetdOzoEyJ-i!G{&{qPqKMtzFp z0KN(*hz%hgzYq%$I3nC>W<;#8l%pp^UR(3IZWiW3=0@1bz`|ULkLW%p09hksFodI8 z09G5ye?to_*dtL>bkTlQ&&jc5v3_2VsF2?OR}KN4FHc(07EKoa=tvIIqs}QC zh`mgsU3{b(x^hO%%(w(;qIxeXoy`uZ)Z{c)t}|gwZO<_l34H@4k*kmHUcCf5q&5sz zx++n~BFY;7=odcFp5FrF!_^|oZfT^#0G`FzTi!cKGq4`2tN>0tZfr?QF*s%V%xJ(% zU2D+>VrZ%G+XK0#ONH!zr?CG?P5+a^a`N(W{(tsPzW>H9@%77w z*oG7^{%xkm^T4y8xlPC6e()eAri5&O)6Xkp{%EQ|FxuRoC^K_&EvHAdGy05_8^j&Q zgp9-RTurx<3e~e=smv6q)t80mr{~^@;T$1m>m4zTI!9l=KpmkM7(mDC=Kjv#Qfc%z zA>XR|{rmliDaSevy5Zs8i$5!!^)^RCw`;7Lw)S!OVHzj9#rXZ~k!1Q$=l8=o8fH#< zF4`o%KG*9bXzJ$fw(k>Q&C`CNrHqOywqj%LhejHjI#Y|N#~yDfRc3;h8E7UooMUO< zwwGQyHEa@!R!{n8Ow0XjU7?dI{puSx?Nh$$Gx?Uh&|$}}E5|uN&jcLBg&#?9J?iJL zCt?xC`dN`)^4S;NugpuypSKpJLWsn`(bm%Qx>PE^80nfmUtG9~x@QmzdfoIX(ZC&e z-$JFi*+(oB4FZI-AG&0eSO8t^#L*)+ltYR?rAZ!xLye?kWg8y-6pia;Ai}FLh6b@R zzi2vK4s$t5_~ioPTDpBOW@G=7$&jvNK$((}zeR1&EMbm=z^tor7Of>t)j~~Itu}w> zK~;br0Ql_mIubPw1%W5|$WuJ)wxEMuyv2J-e`2_f23G7J_RF`|Xax3Q$DLB!HtkfV zl22*yAh}eq0WwulaRMwqD}puh{8ZalNktoCN{d5GFdj~21}BYqa&RYVh?|#!{oY|H z_?GKIICMxbcZ~~r;k$chALm)XF7#C9!?XuYtD1BSsIIrbm)A2jZF(iIpy1@6W7kQn zS2c;@E@j%Pm&RZq;t-8yfMWY0ZJ3~>yF*?KLL>)DA183}|JdhlTn9P6dJ&kDj0O`$ zoBKpv@_rjv{4kdr10VSEyQ#kR@b|VD7p+Etb9t9m0p6VOyE8@_R6ux)fB@TxtF3M8 z!SlS}QMt6Q7y&vRsNf$)SB90@KV9b#R+f4XX>kstLa8VNQ*x73wRxsG^QBycY)A}; z(Y@<`tugkcxP+~6_Lvp#Vz>>sgVtuEUd+`5L_$~&hsAq)gJrn zc$kXSr)>E&c(K_a?QRyK*U7r%sv&T9*DT|PRfuz-P{Sd$Te*yTP~6)nqm|?`TWaNO zH7n|2IeeZx`@xCZY$8f!_6O-nzwzm{x zp?zh6wizxA#D4<4PmTDk=bkDK`(`!li-$oVvt~LG2|b@2!wPu?6!2OSMWwjiy8Yzr z>fdGwJ#J6Nsf+JCbP;JKWDl=xGHmHEY=1%KBdf*sHu4Pzbu=t_u`jQhZ4XR%$#@vB z;nb~Gj+aNOZmZGegr)a34v9cCVd?%s)OCCR17NYyC!=*e`XbozW)`=fF$A|cacj?w zNprIoUoN`4EKy>ET_H@JsPJ(>UME%cyC+6VW1=Q<>cWPMuS4+k(MC)h=f8V4@~1tS zLxkox1s$b~5&=!CNz9-{h#&d&V{V{;c>`w)*vf>_alyI5GrKY_y~Whi;P;u2Q$->hZ-8PvsI9 z3wtlL*`_>P>$0s*@Cq!@Q%7&K0T`h6C0)&*cCwQdXJ}THS`gc(aQ8#z4nt2V|7# z#5-gSE|?J?3t(P!{a>X}pF?0+U4=e+rRSY=r3vzh{%uyw$?{;tgH6EBNMI1Cu=yDi`6(zMT$di$`y8s9XQ%WzTIA}l`u~gJ?ma61NF99=<qvv^T3+|&}7jL0x1kvD$Fk2@j5x|YQMV2k&m%&P zC*0=#_L2x?7=BvMPVGgwmglHS=HwaC-L3<9_$3SPxmB;HHN+`HX>~u5mw6afU z2>G&v@dixqtN(8_uehtT(7zzc(y?pm_Az@<5jB)z{d6b3v zYm~fp1s~5n9sk#Niw)#%8U9r$pI8dcyXEKs_)>;6^9>8@EBdn!CKW!h<4e-TqNw~(#EtTQ;nu#%FMhcUU4MoyM_eSTzgD| z5l(`N%3>6@_&wrjWB#j)hQ6~jlmC*H-b?s5Vr`7k?&D+i;9_;vzp;u#ml5DzrTu-_ z#l--CsaFbdC<9{jKI;s@t)L|h0~FNLDJC}CUo;7GSmPTHWoK;d3;}X`-DdrA?_FJ# z_SM;TH&Zw$m249^CwLzR#*bG9;-MUwxp&y^O#23B0QP4?sq^U|HH5rMs8mUbUquc!$Vkr0xU~gUWKUJ;l{U)T zJXv{GHO-@n4fnvct!_8iVmH64ttQC(>~&-MBZqZ`k`(Lb!I0bP}!dX5Gb08D_T6jMY zeMf6URe8b8Y`Vlb5ecFyrpgSUT$0j^Z)BP8r#HtxQkz4|Z|Tqcc}G37OLp)0D|1kz zvB(O!H($~!jQ`G@&L-<0>}mJs3{`UH`;RLyK5)&33D)ML&D*~eH_70W)52N~kkUEq zqk(O)5%%|0F1DOg_YL^d@`s!MenouRB(AE_@fQDfK*=7bTHhareUDr*7`5&9(?9g? z-;iF1mpfE%PKD?~J<~1yvx3i2>OVB2npojgL_;aZ*%@R9DXs8%&lD2aCO1CMX%+nd zj5?sCNjhwEynU3a{~1E)tjYT>PMb(CC&>e!ml;J2s$(#xGvG=`&z)9;bmOb4ED=pZ zh|H+)=(!hzJ+4aC+Dk}H(^I8YeNOvTGMA91;dNjJ4u-eGpziLp(`JVHFQfAPV4cGB z5beXP9`;AP*TR6k`8qH~-oNdVzl4v0$5jqoPa%UzUkkkE1f2R1)G7Z8pWW);z))Nk z)4Q=IEYYl|GNtSjnWPU3P0^Z2<;F3i=zo-&1Lox>Vc{#OoQDlR9>R9aWF91$PMApP z{e1A*r6ns+*nLgoTDAaTKzJyv#lG3G$}?O z)L`k(Chmk;_@r%j?a0ZZnYLa$!kWdW!~FN!XA);TY44t~J13V898M2M9$R=a+n=Xy z#9yp`q7jwGDXtbB2umJOB(&|GBXzT>Xs?`h9R5|ter1}sX#eCac~`{Nu;8_WP?I>; z?RsoRwxqUrM?7JMYwGJ9^%dyANF)wN_mo5D@H@(ui=39oj_r155RxCYmY z?HlUHoL^1H=;7sIa%@&vcrF5{{3lEWUtX|cE$uoZ(k^XGtn1~ey&NwPrqLQbJ)yc? zE2(bMD5vF@s|9|j z7?wDi%@U<5`_v;Cjw@Ja3tkp9tWvfCv?QHTq;Xv#U{+Jbp3pLSMS&pIWtU_BkReC|zAYHQ~%<#$qBD#40RcV0g| zcIpXv%s`rNvn?nVddbQIV8$J_IN zX41_A-Eo!MCwRSKmLhDo$0#5NX*b^yI#h`+j2I>+jA+_yY19Rtb-HlDa7by#;+QP4xTe%PGnD$skhbYFb`$We6VI4#)TLv54haICC&aGD?*NsyfaWlDKOi zRAp8jp)P$cWHSC1qw?)O!@>Au9gVlxRAg&nnYVv5+xG)5K44E6C*c_ATmJX4jB}F@ zz_K^UklbroSL0}`R0iSFJt>)}oQ4@@2JM`!#oeB7xwSv}e+l#d5#0aNTN2>-Uqd6` zf8(V1{*O4RcOG&trWW9eUk}ab)A786W{eEQU_^oEs_Ote0wmw+&kCCX03N~kAJj%eOzpgu&M18E$V7Zn2V zuq7AG*B-FxA4JABqQszsYNj6m8ogA1CKtGT4|Q~~7|O%#CCCvsR80fbM;g;$fII6_ zLI61smz{cBxg8K3%sKKrP^nzNyno>%{`=_m-#0$kezxRIY4V*uJYy_3pN2@LR=in+ z+-S?B?^r(X`zEtB*^j`3J-)(Yr0Z~#*+3ullqEAU-y-;w$=SX!mQGW#Ujf6B9s4X7 zeZSG`$YDh8C*=4p7Z<(u%$%)CpY>PX#fN6n>Wct71q78`IQADP^J{!bB8Y)9{@LK- zSj&zAuS{6`er7E-@I%@0$B#c6X4Y!|lq7w0pAYk37P+aMw-PR7f@l2M29Gmans@b( zY3E{Fy)0_U*j+{{GsSaxC0tmCbfi*IrlWfQJ}ap>jl2X1`7F^nXSmYmBpbPr=vuxf zn?j^_AKW_grNk`*XjXYJ5i>g4WfnfDK3jHVw8ix>G3=r<8QraC_qcHpH-dcuy* zB4DBBL(miUVHLDTh4UZ6ND9-kBhSPh@7XwoM#AF>kLwc`1hNBkZj)q17?@$k5;nEy zgx?Y3K=3+?)vvY13{n{@lE^N_@QR_PI^oHg5$Cc#mMUT~JGqh*Enc07`V8~~$iu{5 zdqpvop>m)VRZBLR;=>K6l?Tv^J=ZwmG!S+q<-Ar_S*NsQRzU(z;CZv7Cf#heblDWu zunCqn9tYBWkmaYgY!kGik)PtH_+1Q<9xHZ%DF%^uM%hH3XaVJS0f*D^p~|35 z!vt~|wh-hUTkFp=uP;eQh<{JzU>d>zb3B$aTC^7=YJOc|^>dwvk0j%o`+s(L2SaC@ zb-AWJ#w_>IUF8}h)XsEq<|+!{bEpQBnK)v?o=K|IU6Y5IAtZp6b%~B~Yuz+{r>~f# z<>2N>V(w;B7^7co11iJdEK}Ap{;V<$DhKeq2IB!`>$m50phJn@es1_>s7p5iZqdq40|rrMaE5?s`j;n){8LUX3k& zT>hRy*4_Ce!Rdjb0pQH59xZMvp8f-<+u8e?uIr=#yA#Q{T=N#tSqpFlzQM)9twfRt z0)btkfQPGdQl^n6A+Z;m0}~*!@6yxIDU1^3-ztpIX)v=)qBA6FJ)U>537`mG-UtR5 zZfEmT&_@ocEbG`$mPjUX<>htKT0e=$;gtCNDP7J)%hv7v8}=R7)Z}}~UV(_g7L#9! z(P=#_mTp_ZF0o#N%Fl`X2iJXi_t+_~=xq=sV3Tz;5EjC?{^(>qb`VNc6q(6zd-5Z) ztw7+m8DR+bkxVU8I8kGW`%8@SQ&oWFODm&)cgMdDl0RXnAsbQNjURVH7@%Qk_o>j0 zMz}5mo&osh2}R4;z6cv-GOyTKat=_>tNtyE7mZq1^2`g>=^fTk3!EsS7=si)dckRLcPQ?8LPIvC>VUun>-V0WB#ahC;Bt62q<&+#leO)*81!F z!dQGz`7U(&oI&LcVkg;`R#K_rPgSop*O#SO`~;(cTN{NS!JXjl&cX>6+#$HTySux)yDZ$@CAhm=(BKkW0_2gLz0cnF-u=dS z|Nq84W2~{(YN_h4zd7rx>h7AeHMb(Z1UpoAt@9UDnTB8bRD`n`h#c&!D&8C;->yY* z3D2bu>NgGI4d|X42w#Nbg5e?-`e~kFw-WK?uDPWeSG2!ns)8WE>{$*(9It=jZWhfR%jZDFaS!H^42W`%=TT#a-*m57 zex(xjFSq*$sWg(7&&ArR4DWlg$DF#W1zf{gv}1)NwAT!-xNpa6e^FZXKp17pjm4Trm-y4gNg!vdiA-IYPeq}}{$Azz+&nYIB<*V&s>$s5 zRHm<}^w+~rV=w~BKSc8|I3`E*wh|;&%-fRob%hsHVKx}=)i3BWi|MlC##cH<<=Cq* zqp2VawNf-8P^(A7KrohxeDNdYbz(-I2@)&9JbME@E{v9+>B|8AYAc~*3Ovm5=#TP5 ziz#J=OII3*$Gv&#-giU9ncD{TVVrAB8<2WI;Kf(8U=YZAfo`Oq6H!Whm-IP8ctzJ8 zp?I?__VD3=-gGsxZlrix5>fO#FLF^e&n&j0)a&B2PS87Ls+!fe;~0V<6fI$|G-q5p zMaw&Qy5OPXt!NtEy}6%9gVNfzC=Z@L^|waYd`f;tZt9|#~Ir1dx>%7wx zI5ki^(LM?aEJyQhhux|oGfg558tov3NgWgv?l7loy?zDWY$#>VtMoKa+DbqC8<&+^ z7g0`U)kW(Zj&jhxBUPJxPb=G?I@C-0sr78)6te#%1`k?v`Q zZ0mFMJ7kD0EDY9}O4EDkj$to)J2yZyMNJ_nrhSDW7g1Fk)Xse}lL&>mNauAPVD!OL z4$dv^=^lu4wY5GM#y+)y+rbND2IV!3Qo%-gm{=;2DJiw~bj?xcs)ncK0Ks9&oOtW1 z-UsVrkaNTYBuZQabPia2ju=^WEq#7}V1#h;%AEfE7A?YkB=rnJROLXnnif zPC&Ixjjd=F-?Y6vSJtyqiY;|Zou;bkxWo5tteoHFsEDHyta4pf|7J~cW~GwP-*%HS z=c;2LVDx>+)fVjr#hJIRovSRu zpX)@PRrR>qKl6wLdhu(GrOvhN>-VGxhSs+)55Io9CMZor&W&699OSjf^XGBzgx&t^ z56++Tn3fIv3}2R$lxuLd3g6kX`dd_N;X_8BqovjP;6Jc_QL^UG=n5ZHl+g)Nrj3h{ ze>}q|F$Phn7QN8>rm8d?f+%wjHG9Nx{E%g6DIVe=x`oY}ayvd>g|2L#Uh__bHwEW8 zStivhiaQO$7>mW*9{mKbQ&$gh;a$S85y#Aue*jl^Z!}%2&Lph4_=X(`*F(xRNOuJq z%z&Alp3%+Pa6)&mYpRJ_Jo?}S&TV*s{TC+*ns`Iz?#yA$!Trfh;|{JbRE<*(7nHmr zL#s256BLK1230w1Vcwd(K3ID3*LKzfeH&E*nD+tjy7?Dd-kKX>T_+=~NJn{+sy8e{ zFQ(0*Jy|w~;f1y#KX?YxvRUz{o=b){eM%o`$ramWKS-rnJ4GZZ#iy*4NaO4&Z52Y- z6!_k4;eGhFXgoj6Q+Y1h%$2-cX8lvf%7@b(T+UjgnTGY~itWmlb&e(CazQE~sWMOV z>*TYymHeWLgim~~4cQ?ow7To35H-mdz{Uta=kvOs%_*iMDL;Wcc()|-GdjdO$4=?D zz~j81s{UQTPn}?^BQ=Pmhtc3X@wp77hp!!(=ha6SdneK`;NI&BUu zntqbqi-iAYku9hOmK853lqd4xvQPYrJ7eQ10ELJA1l>RB>E81gTE1^+H ztB2HlNRfoxf|$~ggxhvu5E{DE91@wCkM~eE>)p90+t465k|~5K-$bUvzUF?W4Tls5 zD)bazeRuoZ%yuaA3255KpBZC@9u~-M^?V$#+}Wkhh+MqLB#QlwsQ+TS8H zh+$9S6PXWMB;;w-s1rsUZz$Dra3g7VHAg)c3@^Z^PcYq41%LKWTf=om=5=Dai_StB zf}Z5WvAm)S+K8KgJHJdXJ#C7M_(pNX=%0GT>um}73{4xv7yAub#Si)zm?jil7Gt_E zEQS0iP$G<#6)WnZ2x=$)>TG|5q-LE#0v;_LF-;n*9eeuDuAq>C4%8F_lQJmF$sIDX zaZzfS7AwLQU_eL6YMS<*a7#S){U^^|tjN2lFby9_4ab}WM-&jNSi&0QOwfL;213G! z+aUjlOqaO$4Ic1lkUEV1YJlo!fIwj!)oVGs?G?ApJ|crP!~5ouDL@0OZlN#N`&5{7 zXb`{WR&1H7;DiW{Oh<>Ckg2O8s3_JHDNLn{;S>)c@hqE*70sasppC?=C(DUq_83fF zr*>cF`83Ovus3M?r%|t^=F*v2Q*1#(N8Me8*|MKvc&DB>sIkU`>;3A`(A2Ft$MPx+ zk=qBXM^4|Ra^2{DK5-KSV;nRp;K#^vz_QN-nI!BjA5Kz)4&&E|=hJ3or`-3=rXO%0mvTdZOFHPEWrK-}d6*#`H!mQ?;t z@KB4mRhg$R)Mli?mNSIrNNw|-<;}M0qouhD=aBB8Yj|%aik__wxQ4My7XFxhV_o)Fv_21h zUwQIY7Bak6H^T>HSnv+o=>j)idkR|AuMyuS{rM&xGGYRr$0g`8l>DP4FR9ZjKPmSV z!Ni+L96QqRPH)uI$~c1xp~m1YYVg+FdLw*u@UzsoMW&1Y^o@ew`^66AtfIBsa9$^F z$C)R1(I3M?h+rAwj!uOa?Xp!V;#O(h^4jfuaHktS|2T%~zD(bCVzGLV4a9{=!B0Xx zA4zK_eW6K>`#XYftO%0$YFL+PC&Z|repsszLgVpbre|Ih}gUpXZo$tFuc4l z41#aVZ#6m){%iZ&syFz*?=${w($D`Mz~69K{(bDf;4uH5VDt;(A9z^)B=PNB|CjNw z{)!Wq|F87?e)Zh%b${St{bhq+MEwWw{0brX?|6RQ`u#6>{+zk>zmJFQmuviYJpZ=g zAN;WWGT?uPAGUvU@t6Pnj`jaLKWu-FU;YF9{F{rv;rX`>|K#UC=g;i_;LpG3^!=S5 z_Wztev;Uimzxet6DC582`Oo{-wdcX_tp#|JN>Bgl~*Ey(u(+@h{Q; zO9TH~lX}}(&r#3P#^g^d|LPY0+W&8%N53WW-`xR&jGmPdgFG99qCA7R;hX-OIl3_j zh!Xy8NDNAX@`V3-j3oP6nh?OCAWg_f&&c#wy}vt?KialD8_aKW{%z~uJX`)PNhshq zl??Js02ro!O&gVGVu4}$*RkZ8*kPD{pFD#+fC&ch+g0EGvcdpY4^Y^?OmtTh;60KfWAJ!=yq4LZQ@1pzZh zhtEd#3VK$ymPUjeFboQ2?nW9+tZZ5gQbyJ$j;4fww{vxHv^UbTf^p5XFvVN}0TKG* z3;L@o`eXGUPVws;{@~&N64Sr%{U1Uy(ESAo^zHKxkbbfKr)~bmJ_`#B%b%40We65_ z7?wZS|7V*pv%)a{%NOLCIbfLoFeM8BhUK>@|7M=QC0F^o)&Eb9`|pGOt=hl&@c-{> z8RY)~`0w8A9|-$rcl`&5zq_A5EBITfzj6CdrT$;+^v@Oi%{c#1*KdLU6T#nX{(n{1 z|2pBn<@Qgs{|xaT&XMJBxPFV-uc4!mk%NJ~nXRMEn;5(;{#G?%K_wY}B^pIVVJ2aA zMs`j{M@GiqTLs<*)^8fXK}ZMSWG3X`U?F5@dTaAl zD`sS7V*1D8ujBmM_NycegZP{1ni=q0o4m=#o6;ya8d)h50+^X#7^KY{9L%guRLl(D zRD_lBt)gGB-lV~ZiIC;L>Dlk)KWO-u?f?jx0Zi;{4F6L~{uCyTKN{V?#p%oo+Er0_ z@vhXv#-;e4?1(4pT&9>yl44_pU0~LbgeH(S7Q`=O37z`YZ$CV2*6`reR%xb5sXEHdanMgX*)=Ez`wV0bcKjyS1qVkowNLmUT;N`RcnNfpznHMwsH zvTr)E`O<@a@)_YAJGigE8dCuy#Z_PIwhqE?!2nrT$(wev{#h4Pd*`$hVl!~1RBmuY za`P0P1gmnG^K{^qO0Z@q1rfUeiqwiA;zQrNOHqS**8}`c`V6V5oX-nSq9dBUF zHuFO;NE|YWICa%%duwIEGZ2bSyNXu_{;V?O{iVV8PtZNb)|*n1{yVb@`r^YCp# zxO7ENv86ZthN5FxZ^+(IzNCwj&Q)%^)8q2@-AvK94Q;K+-z zu(iYz13#b!r?=+)-A-z)BR4Dfdp$nx$Y-eNeNb08Z|Im^4*dQ&FNs7saqgEh&Xt2X zTPSacsW0{4ai6j2cHLY-5&CSl2M8R$sgR(gyF+`wX8=~>`EB-)y`rhtnEQs0s@cs0c`iFgb1@ z&;`gL&>XreCK?kxDJ#q~cexy7_ECTj2P-4w^AO^;>ns{iH!B-<_m_@#xd6MDEH#Vn zs3?TFdxO-FV}ET<+_{1J+PK_XZeIC2w@Ys7x1P>Ji4{2cqLq!9S1UPyH z4R0(JsRam8h=p^KKkW(eD+)=o2uV6pa^8m9?}fiM(3CN2CPbisiIa*SGEDRfSoTMI z&+*HLCbWnjr&=t=(a?A75SjJkv>T&Hs*8?(1cbOreU*xrT-+(n0T)A>x)vj%A|@+< zBjZe+9CGB;9z$>asL1Ccb8)K1?9tZ#k!!WMQ95gOb#{GznX$F2s;S6bzNE}ve<1Lx zZZ>`=Uzd=AtM5Siy5J+7xOlj#KtV~4DC=0Hx2s4*;kPC*jRut_CQbk3Ekk1-bCZ7YXZg^XoR2CuCe zv+Lw36mp0R>Y^?5f?yBa3Za>J>K4@^ZVSY9+%X!5c7S z+0>VojD7X`>?0+lJJ2a|DqR@?;H;fzgcp@3I*iL~mF-oF=g#+`OeM%C*olj9qy24~ zl4cp(5=-Z&0UFiVvppTW-R6EK{6A06`MU^Ut-hT!S$A4~z91OCnMW|T<}mM}XTTl5 zn_q-~;!#y|_%RGWoZDZ1-O}U@z3e(wD=U+9Gejz1eJ+_>+z>%x-g|QC@TEx)w${g* z-D)gJkSH}ItY>1bO>Gt8`cw}J;)N$blc3X{(R*N7xY{yW2aD?Kf!$nQ*-6Apm6|@* zI`>pkLewgTPv=9#l2$-RwawROvcw-4*0=MEOr1{7h{5KUr1JzP78~d5g!>m4eKNF# z=BbN3m^T%eQdf%gaFn()0M*qQx({LKI8tR;fnATa@&P?<>Z|lB8;f1)i=Wg}Ow{j5 zJ|lVAxa5s>6@$R!g)|vVD+UDYl&`IJ>dxfWPj!KuImDH(o#VsZ=03S|Z@_vSQo1kbMl(k=wV8lHe#*PNTWek8o+} znxcx}?kvHRy4A@Fe}f_$vBv8iPqA>f^S{oPI zYFmDljW}mz-&~7sc`>lPm%gd7(*x)Q)|mvFF79CBB*XTUeY}Bh|JblWWbZaKelE&r z?WFZ}1#cfpWlm+Io(sO(iErl}RG56UL}@I!CJVoX`H+x*>gKB$ly1GN5)y>I`zsQt zTryG$aw=axAdQ}W_cJ-8npolt0WRqniXxzG?c>tBkK7nHv@5Gif)p63wv?ACa4525 zaQ4}w8-WRBkm%V#3jq?ctVt?zZs-Y;rJBLPekb_UAx{OBUidc(rk^)-DaO&<)C(;r zvCmGO37QB_?0}^cBIBp{i9crUB|D^3ZJ2}!!YL4~vo~eeK(#g+D#q71y5CQ*X%iWn z;U*fuU#Y^U0<~!cCy-$$hH862(Z*~B`?vP9d+_->&F*LMXEL1vrnjhu^h}&2Ja0sL zvfpl`c5$%VQB!uL$i*A1%K&Md*19Jj^xq31nAkHei$@TjLTxq5k)AlaQrM_n`QW!Dlzy9_2O^LBCIVmg41&GoE`f?L?;i4-q%V1 zLW&2KRAQOD7gQbQb*ctljy0GDsWOzl|C3Z#ln>IFYThMF$!8h40FN!j<-tM`6XGAS z7Rd0SRH1626O^*T1yJ3Cp7)?r8yFj8H+mY#&)mo~kJtJK7GEeW{jFx97PVX;TaYF5 z&bVshK~Kz3%PzH{Mnt%~p{B4V^T+u@yi9C~xk-+Ee9dV|jcgb0gKR;h>X06W1XbTz z6M;GI_H@6402F-wKpwF3L!gf52{h<4jK;%(-hLY4GiDPZJ<2&40Yo?6wRK1XX1l&E zp*^w^;PFEj&e#ih+mtUIadx19%zF(Etp>!Eu=TLiz{5|pLYXo4u)UP}^FGZgE(~^7|=* z(s1BJc;Y#T&O!o_XT1ToBljZ6%Y_;}eE9yp?tE~gb2WI>28?0PoKpB9@yx?QVz8Kj z#>@Tpp9JAh2Q%4+*@#hc`OEaabWHRzhgyXin<5)d-*|n|LQpI!o;$Al~|&DDyVMxP@+0d*3p zw=A!e9P#Sl-FWlCYawglYGJ-Xhf2RgG=cs0mcKZ%3%!r&m37_?js=l8M}y2BJq1qO zlg~0Lo~H@of}7lEgbBsZXd|6 z3W{OxKK>IfwY8g&vKz)Z3}Go&YZEaZDb+{=8EX@9dGdCb@c@nq`MJ7>^zpsxV1N&l z*PM;5b)+cBvHq6ud7vw%0D&k_qVIVL53X>m(q!9`Ctd6-_st4_s5S5XBtR4t5=AQRs=^VKYgJTr%z#wp^W*4uk`k3xn5tU`C+mOtJjU4!2c^ z^J~ho^*ruRkS9yGpk))UCDG8{`{)G6dVtOK?i6Nis z+)uF%PoIbK0jfSXJ16j(8=gatw<1~(omkMGS&_tirfV;ruMc}<7ZZ%Qg{Hq2?SY}c zmVSR$cNZ$$_UmD8f&lJRl5HbLHW;8{2$23h8~`wgxB;a+*z}hWht`fD`hX~tSF6qa zHJ;R0AQ=M2F4IoaXvJWM0|LhcyLixmA&&q>=o$H?*JfGOprTcpxX)8Xu$=b&35R5) ziPG#NrABaScv~8bf|0`IvoX~6Q*OK|G8?U|6$utShE*S)AZPTww;g=+kRTODvKz;J zdLVzt2SM7wquk4gTmdX$zVG>+&!is`I)YoMjA>ZT!-tTo{nOqJtp%T9oI#u!MA*U; z6BLO9=;OaqE*ivj1X~VV`S@$UDn#ngV_dU9YxMX%;+2TTE^c{E^>DYm0w+H;R5Hv| zcVqY2HKetEre2SE4X<)BShO7>0CaJ|js`85dX(!yd|SqD39hnez=w&{i!T_^jXgDR zrp?0AD91*=1)ii~8caKpL+m+L;#^MX?55HMn;*9a!2)bxwSU0wNt~&w;1n(8O9!uX zKET>_unQ(Ah96J>WYj;rq*qP!l1^W{7;Nf)(&+T_Z-;*kY>D#Ud|!@)hvxsT&CXL> z=s7h9Z0v!)q|c5yf=vtD#U6i|as?hE_ta7j-vAc~QOhB_mpVSl6L!l3jo6QMR`%Xb zA@dRa%cW8a8y-2$L&6@D6or91@gN8)@1C?RYcVO+OmA5x*pNQ_SlUojvA0Aly ztsyhpN>hu_eskBw(&ugdP$f+J+~mm}l_4uYkWT>6az$9R8#mr^gUOHVh_E;rsL}R+ z)v1Fd)I;&5#gH3QeL`C2_v^AR-7_0b>G0#-Nh!HbXi-@~M5lDwb|bNGpN6M%eFe$? zFn8n0yBdT%h4)NA7_#Yia=~YZaN#QxD5MT<1nn@bk{M{IhQ4YKy*y1{YKafh|f zg}{3FQ{f@THby<_z_)yT1xQK|HxNIi4y*1?Xy-P34 ztNeO*m;bdZ&GSsP%^x}V(*!u$Y&sh}gFsmB4)F;W6@AzE=`^_@pE z!mH_S3*)@4C?L2U?_FxumuvlV)`pCfe$~P>ZrIAuk)JYZ zno9wyi({3(n%1nzIA6S;)MAIMd}*r)PC8KJTO4L4yKTCbfS|lM5@abvRig9#uH-xF z{m_~=l-428@!iC)?@$YvBDb9d>9Ut3ls`4?-J2q2i@c1RdqpM8L@iw()D>3&X20D<4+){XK+5*slD!eOe|tu{ zcj6e>#@%_vlDQ=DLYEm4d3q0I!1C&;@|u*-0X%U5cOzd14;7NHF@dtF->V~ejc<^F z-HcDnKt8||2@trA#yJ~8dkYG@??V8a_0S7JKSIl51TJB9 z4jw9rbelK^&d@|^8{cq=FaX@+W^B|*5SZQlX09W>`>cOhBwuriOfk6!&s1aL>EEyb zi!pgd4hex2s#!72Ph_aPgNGnMQ7oQb)6ki|$UElMAyWn*Ph@YTb4bE<93<8m3dG7M|K)-3?LWQnXcpew^^Ytfl6LD zKn=A^4a|-4Lvj&zrZ&H%_Usv_$SR{71Cb@h)yYG1`UnoQ5 z*hu(*v?6JdOqhktSAeVF3DnqGOt)TR^N~_L2hR8mXsyW1NO??7Ofu#=<~l$fQyn7{ zGZTQRj*GOGiH`Jp%oh;S{L{2;dZ!*WlqrWHj>=4p0^g&)^0c*v<5m zIwKnS+Iu*4>g@xQ!7b)v=*VIzFh)$k^h9V$E$p5%_ zR9RDselkg00z=1dRJv8Hnj1A}58G4a!T_wK$Lw*r1te4CgFg=own)W`+9MDH5k>{{D8gb|F zIK_l7ES8z!j0)qO?rJBq&EG;}X8Nt;-d+mWk2@#Dx@eMJRzy$YLdPIr|kv7`Q z`G^Lx%=th^GY+#4vt*~MF{+ahYRM4-?XfWyCz(ETEF7B((ssN-t|)d$mx1 zh1Pvr@a^#4CHUC&QJ59SMi#&vsL--p0fO&}={gnXeg7_w21KC6ru%z|oM@xd_n1SRXQIXh~(#DEYCDC$pKt&Pj#ZMR{6hJf) z1d)-*(@4w6ib&cDL}QVnX{+JB(1cJMBnl**UBXw?OY|LrPzGcjLf)acA8?m0{W-`! z0?){HXqQAgVEsQh{6ml#2(v|>AulcZ9YRfzrwF}+I09X<0fDZVqE3AJ1o{m6h&ya{ zf$U6pI$uo9R0%$*_nHFchKNOAvFLPJa%Q+iULv0`CyZD^v+f)zQ7^@!=Vl3M_{VvJ`*!Mu#*5DAoKhuVn36&6DB z;g9MHf8g1H+ClFh3*98r7U&3lpfi6!?l0_Ea)TzYeGLWA#9+5PZ!mA&W>aYjm9X&^Jv3E7fx%2l0S6#bUAEL04T5X}7;4C^vcNey zA>iUY==;iIAL6Pq*0^sy`H@h@zBuY$e8~g#rgUdC#H7sn-0ilN4oVMQ?ZEh{LGcv- zv-znc(u@U4%#X6L+cn>!xaZdn#=^4mi%YR7eSA_vsr@E6)Vh zoN=lL5Tm_Rvlh=5@fNj|!<4zVm1y8H;MZYZjCoSZ5s!3cyNfYC`4nf*SudSWpU++? zG&(f;%!xGi($lRJx(Qt8lg|&yE{reGE`3*rPx{^#OCGCIt;Ds!&#Hs0s8U*7_IPHF zBLDvCMDV!b=81YiaX}NkTToblTF3Zh6HN{RLw+l$djx1tPfhU!6@%!LqnPJAb2kRS z$CJk)D6dr#P=TtIjg{?tcEpkVvx$JKCbfXQD}I~zFL2TsoRpoONNvWG$6uv~7kJvC zRpvNTg}P%YiWoMU;Bglw0-~eO8GR12qK~updnRtU(NLyv=2DNuCo>UBiphLD;O68s;_QT7Vc42aZYjC~~bm25}wZvI%NskZ< zd5-+HxRS5rccjjtg8_81L=<`da7@=E>W#Sl%L2-I^6v%ehLED|d6Kgb$z^5K0j(8^ zI=SqL5C@Y-bTy6mV-$;9nc5lOY`uF1#}M#{lLZ~zSIo5OC#imvPArSczGk(5`}Xw0 zqn#j5eOmz8;`o(r?t8XkPIXJ5;uXXrRi@hh_C~LD(!652%ID;K6k{RFGyhe&Jw!Be zaV5ic#e-7X)XzCpDZIk?Uu8ZKeOTm8%L0w>MiyikBUFT~-fy z5sg-wK}6wp21hsaISo;cOF1&HwPEmc(@2GGf)nc62WeS|!iPwOn3DMi$tY){51&evA?UnlN3v;sr&c$=F^rU!m)-0BMXExKHl|R58 zm$eqVF_sWgDLmDSvc`nSO-(f3ltA1u00l-SX6?Nb z-h37lL_Xrj;IIe9AKeZaExfXJQUhe}H><)yhq*#@K!1q+F`*Q)T=_lo*0zp|*>g_z z90lI(3LIl&*?Vs@vHU^tyQ7LQnB9V|0m%sKA6Ey=KOnoi3LQ>%)Y~OW9NsQO&D6{i z7GEv5uih&sQ;@}-X6_i~sFkvCCIp8l*jtW>hiAX%?RFaae$Hv!%+Tt)LfZX8 zuq3lpwTU5rxVj=B}xg1{=kbNy$cUL7|i)cOCjp}@$6Gepl7HDQ313cpmU>gdS%Utq+DMOtLYGm zEv!tHJySO0gM2pCni!W?mt#I(<-pT&zL`|~C=?(qP@=G&!$Cex>4REz_&r&n@13yl zWC~g9)f_WS7IgrtJ=bI0TR`+YO(9H$)6DlulBSo2_*+HJXUGGE6ZCfy=uZtdVzv+4 zQXb>Q&iWTt)3{4b$asM$d#lbsQyG!AIQ-oOvF|m@12z-3W$h6zGMOb=hrMWh?dzPi z-X(82H)At1;>}d@nA@p%={KLH%_a;DNO%xmR3JKf)G_4C92_Qka*1_omxEg%Jm#(x zsUfnt;mii+DyR#;fsFVef#(n1A9HI;;!kGAMr5Zs-6%}(PV}sI_|B&RCRSKczD_>` zi`cQ$j7$|9xYO$BcV>b-+6&Ldu;mL(HEyyg-m~k2BX^H92g3VL!-*wCpwmQ z&z_Atksgy)wu_?y4`60zWnD7cB4M{5O(Yz}8{Nr#54O-sk6sH!s&qC^dwbqgtT8kW zGQ=)AgY6347`JD`iyNn-__^XX(I^XdUtHNOT{)m|$H7oc-#4r#CaUk%v647cnp5o z_*6smN5tc_w!WW!A9p_*mkqQY0Ma6hX*d8u>=+M&sTGU`^&Y4yt}xG7i^IDk-;8CD z67N2xQ|Kxr8d_eX8yAsfvph0;LiS#l?R`==|5BD}B~wqy`nAlns@ZinF!+qFuO7{k zi8_!bfZs_%&Yg5)b7m%4&c^|dT_sOJoRr#82)99)FJ6^QTdaSzo?OD;+ ziRCags=m60`irRk_sZqhPUz zs&ca5^%}9ZUX?uYlGuuK5q^4}<$fQQ)$GH}VKTa*bEb1s-RnwLs zN^&ONHFIVp7COTKAfA2$(x%SC(Ly0;KkYG~ywlX*ElREA7A)dS+uzM@m|27!hSJX( zr7lIQ{G%E@(q)yIHyddXvfT4*pnKg@#*#|zn^A1Xr=jD4ovfH=f&&JHeX%^J6{jTp_agQ zx=gh~jP4|)>4CK>9OAD$d9iN#nv8a#hUbW_#c8_;Mg@FE9OsXs(P0)|SY-zHh~-9+ zq7nyS&t}JfGzC}ekP+LqRB3YgL&^KcomF#bF{-JlQJ0dyg~7;<&&nQ}c9_SqbR|u) zD;y+S2ot5YXnTgF^mEk2h)F6G=zA3_@~dj;nPv0Tw!ueA{aH)$x)G$&hu1}?j(#d1 zrc~EH9-U5(3Q3Eo84w;{e}@&=fDB`~GVsu*yOmd(iDC4;6ClA2tu{(%$+#>0R{X8} z^k$7X7v}Sj);pN^dL14AkW%8R_;8|lRC(z-NhU6-e7v;7xoyB);79cCY%6%jp^}xb zAAtrtgMjY@WzLS|Fqdg!=o*Tcv4gX_?8)-4WyujffNo=@d+-eTFO_~pxmIol){=7e z)+Zfg*Xj-@kj^*Y#?4CPBc!+t3N%TrxAl_GMBM-mr=EBS1^W@Q2x~1(Q~RRTt9O&M z8M9g2Y$i%ib>&yjt*GtFvL_phIMb@~@hrwM6LES9WbJ1nHhFzhRn-EW<+dr80Ci_- z#{pv&F}sx7q5Kr=9e2i1K$pQd={QA?U|&dS-s_kqkjodD%W>!>5mUjF);axMqxTv(XD8eoNGNux8p_J7HcK!AsPG-b@I%OQm!+W)e4w=M#%kTYxZf z!h#%$SSJc2>MSb2MV%eau%A>{Mxqs0{!S1t3*K1ILD4*3irlruyN5m!)N{&>%1~X) z(SQ=RsJ9I(+okJ#*zcfcrd}l8OA{4FvGIHo_MuVevqrp(@pqe(ar3bLz5D!0$HN@D zl6qRxC=Wzt7eUoZ`l&A#qnj|`-dNFKU`4A_ts zH4h>lywQ-Bwpf{|jFAIleSCTJ_=KQ>*sjpHxd{(FJze=lq}ssKi$WA{gX1Pe`oz`b z)s#^Sg{;y{2{CDO+?F&%Gey%!gox;dk22utht#O?2KqZQv1Ljil8pE!4=eS3U%$3? z?nKXTdVH<@dToo1M-80PNM(ItZx+$~c?c#A2N6*)8<$#=OZfqLfYhJE%4i%m@3~mzEqZu#jM-w3 zjA;`;Lx|O5p%wsJ6^zRzXceMMh4(oM956C`hq(DIQ&0QiI?*hy{Ezh0+qPt;8KtBd zj0Ga`lhE>f#ENmFTHkPl!B+zHAoZVK)llQ@gLme4D=;1pvsvKCe1P96y zQ*l{axNeHsB02*UY|t_Bki&u&iqzs3+D*$ZmQTEVq&87}2zN2upLr7rJaV5e792+t zzCAoK7>#v1o*EdPh6@=}*`y<@cI;-xr#tawrOc=+7{*IJkY;^VS&rqi39HO)%&lpi zFHSBu?9H7pm`UGY(=y%tx}cH$RWnSoL)_w0bu7Tton33q);eM7$btG)ZT@TeOiTx% z8YC}e0FM5u{OTBj?M;wqtOk}mY1>JX(UCKM0y_JL%D+2y| zXWIQE_o!DnH8zL%RsLh)|Js53zxbs~%@ zV9ne7xYm&37ez92k6l!O^Swz;BU2;*+vw@n8njCNIgWh@e zI&HOnD90U|Y|~?~$R-%)eTY4dCS6-_+=je2y3Dm8L|+IDLYRluz&$O?D|7|mZrJ8j zgyxl{iSQLXxm``{vzU>)McGQWwZeuV*jhoqhvLYinVB2HxA1-;=2js7>A5!d%$mitc?Xi8*%4bX;N+5%iA;@qG9!NsUQBfs?~# zQG;FbuP5Qbv?|WG1`D`~3CDef(yMAhLsRZVd+DPeU>c&z3_3e83Bza@v;qMuKgz^* zp7ao%qB`sA!aVOML@%`DUIgCW#fo~?-SIPX=0oPJ@7D*I-~fH5+S{=ddSM?6rXlBU zy9Bx(%DfuYXTw)W_Td&X{4f~mR-tvmVv7gW@b0w&4RZ15$ZG-HxK3VjOE+GVTLvA&O&X$HA9_Jb~^#V1^f(Vxi(wp zmBe+@E(Uhpw8QMWu0EUjk~t{^hLkTJ7W;~dh*DFsu(xQfG!j=6`=ve5FGtyKQ3{h6 zqjJObBs%O3Z^`N=S4)#C;%@WCg2ZD z$l&d~JZ!I7?q&om#PCPWB+8qc7>96u(!XSjPKUT|GW;x!xg0>3aSkrtqxEOIVknQl zp6zfODeG@w(mC(QcdbA=5Km#9TwP92$7XkD;w~*6meXPGprOaYp$IIaPS)hic{;5J zQVg?=purWaf5z}ZFxkoWHDuKHECiw8^wAkEvoNgmLC4{H>OZ@&F!AJ!6I-%1=QL$9 z?0ZP2P@Y%byBcOS+jEj0G}n<=Y5Xk+|qf&Jkkl4-Sot@gU!o z+txF=R4>3h`VrZ`X2Y2npuAM+iJ{d0EK`X&f`u_nC2sPVaxug`6Fe;qJer?4q1sqU zUUaoqFm9D5vi0;Q=HFpi_WY1U&AG_F%CO3(cQnAmDUsB3%1GfM4HNb@m99s}#hu+? z(G{e!*7gQo8b4Zyy5##DIKK7I>`dGQ{ZNn8t~@{?H5pda$n6vIb+6Ykm5ph1xW^r{ z5zdeACmtPn+lZ8Sk639C)&aCvs}FLd(9q)N+&Rr(N@vYUHe-Dyj+9Nmq4;@sZoj=4 z^GMnC>cX&Vlu#mRb-sW2BrcQm{R!WS?+d$t(m0L9f{1?)P@aGOQ{ua5X96#N<*7Cl z4}S7+ZKB9+fh?U2>^Qz17mP;HT#}J8i`J6ztX4|(l&O`q%*D#| zDfSFS@f6m9uT08!jQ*()&5da<=-NI;?)n2em6asgSVM#a^x;wb%EU_U;fI+-!lF8; zyU7BMO=T_hO8NB@bw#Yvhr?f3&^+w%Rc?F=_wKLf2QRMXNvPWkce%K4sm%GEZh$$~ zUwCSKS26Fq3_p45FxejeK+zDZvch)z5y$O3^h9?d`Dzq)aoHt=M9l`5)$MHSbkq-z znA2@-t7K-loVqEew5n#w{>@1_+3CaDuqX{ddq=7J+;ngE>9`1*Mauxt~=Z2hVS&bl+_@%?(W~X5NUS z(rA)2=}tHnZAJ5Sx=D!I;%^+~Oq(q3X0bwP5%NN4AZM`i(z%bv!dR*YDIhC;H`nH8 z=i~rme7Jz35_l!gSv)jnX{tGJ9X~&q-I&W;j+FCsd9}-XO)Cm5A)s;rabXJ&B((_d zNlgksHChM1R7_4LFIUj~Pza8(u;1V-%`f<)A^dckq*ylY+hc;Kx;D8=N#v;p9f4hr z-UZG!aHg5qFRq!mkw{ZC2m~6JuIHQ3rHPk#=*PF$?LiMkR5LZ87x;JiH%3%5N6)HY zNt5Gw5x*zTN0rKn!h|@cxZ?$?c;*3`m#VoIBf5(_XrWtQ88*+}cL;9t(rDN_iN00@ zYbHpDeI7}A{j6eVF6SQaqJPq`820s&RwEy(Gsw4$i*#^#yU_`YqTu?T(viUIz3)Cy+Wr(9UxcE`f=iJo-}Pne}0); ze3DkBj*DwP0B9KP-K#}+8f@PZ9W~qM-svtt?rMK{Y_5FJZ(@vaPIK>yjeFekNt%E< z4d?1mCpFLz@NH|4o3^dVfBRYR@#*0{+}>M^Yn3hr zoZ^{)cNfWTD*VkK){~L_x8O*<&CIX9_6j$M`qwQ`Rs{YMw0zW4Bd}> zwzHRqZ>i#uS?J%KI;~y=%9Gct=8S(;%*??JV+xXcLcgoSau1sQsOv`?nOZVMcH|@n ziK>^)!uxo(RvCrghb@rnahKNSDyEh%Z~;-p^w)y^#1PHRBsme=KXGMfA28l>EBST* zU3k{qT&*y6pdVvRHB8?!4jKv4->D1?dJLJ!;Ky-rJ(JP``1f)1@tF zJ5V~f+eH=UJa?dX^e2ZyDAP!eq)RE&EXNa)z?Xq{VzgQfQENbMBnmFyvlmcqtu*+} z!9@QJRpSP%UWs$yF|2|7?bBte&;`18U(u+fJ8n#8Y(hLv>Dpo;E;O`Q17EdrGT$3E zi=&aN|K#0v!!xUtAxp35Wf{dti&5%8LO(60gLeN_22;|>(@s7@nSR5&I@b})%oJBE z{G+_U$%uY@oJo3C(ru%++=lmbRm?2krx{J|SKs*JKh*TDL4@%bK#-IzAnRvTV^!Fp zQW@SMU5B9pADCN9B{o%b&)@{vjmrsykulnKr*LY8v1!p$yG8}A>L6sAhHHnE&8+;1 zQ4=#N$k$9mn7kDn!J~|tSJ(H*77tqpEg) zBVV;$q#()SIe6{72=0(`2iuG4KI{fWs7yU+(8^Ce3vH2j;!nB(BmGSMd7$U(lRSfp zE+J`XI}_`(z51Kn(3#=eL^X!~87cn+3_mlj!^82zUO?Q!r+%6AM(@-q@h4l}OHWM8 zu%D{x2NgnI@ka3;;;qC5ie8m!0&Rk5gc*Dl`5*11!W4M;6UFC5A>N^wDB^S+Pc5^a zof_(MUh?LV1UofJ*U_PlZ{|*Qb{;&vKza3pk@W+iJs5sG_j89Z-$#<5xj#s4lwq}T z(+7uhW}_yKGBMMBPWpl5t1V(h&4p`3mV6YexiX9oUU!>odC^jbfY=}exxnD2sBfDI z8K#M&vYL2@+y8nq1jep0p4px@<2eS91uG=a4+|W$+AEoxTPUeZoMdeMQhomO3!BmO2yw(W(Y2(uP%%a>v@ES}#9z@6L(WUq zIA2*bW-~j(G-Y&xqwJ8Pd%svlZ$K{ok@cT=c|~QXC>Wa$9xBMA+kNH>!}vK;urVPE zctYgoZkDGT?=%ms>l900-a{ox(QlO{l9*e623lYAatn1&``+XX(qXpvK?;+8ht2^F z9ykn_HN2;dRD?A9BrTUBnX_n8m&mW`l^pD&N&=UX41<+|RF?WRf-*(c3bPR}-aXzy zXTu_m5|61-pX5_NY@w`!pxQ85UB`?b?q%dJsjQ)7Lqm5k=UWRJG}%FF$}b)4SjtZL zlWv^oHj%ak*sbK%GY^#;W#$d5&w5_6u4YJ}o!xUa+a#~sujC$$EncLGiB1Jb>czU` zHYOWBJe0l2i3$r4Zet$&M7>(hCvldXE7(8=o25L# zIUK_J?)clE^KXZ*aN7fJ6dU5yy8A7t9mn)%ml9sqDyS4w%NeQ2K-thsOkO%ay8WyP zGsxNO^5cxU*^lxLvc8$o@`i9s?dzkX@_p(_`(7KzrjPX!W`|UiSPesTBFHM(hTETI;wTIbL61{I3PHt+L8}IONqMBwhGJKB~L`$aRH|@o!ECyB6aXpIdXw zaBL?9ZRx?Vue%6=_kGya_YZ_+V~n#lMk@70ow9nWPW5?`8A5jYda8*s#FE1^D0pU7 z4eO&yc*YLPAK4(&^RY}xr~;zX)mYg~w%$LNjzdy`g1Pc;`_>Uuc^Aq6tiTtYhZwu8clkV9nHK+a6loIw7 z)J7RrjlXt3b+`TE&sc|pE_TkQ96Bbi@!UI}Y{OWHln@-HS;xH2I{c(NU zJ$zya68>C59H9Kj8V)N6W8Bq_Yx-L|Y~D0|!8{mu@btGe?1h=J=C2qHyhlPc1Z@Q* zk9;mv#wdX#71x}M9e{9D)qsq)Ww|CG4hihDNtsv}5+~l;0Dd;%(1f%#aNSufW#lK1El&d)nl6315bT~OA6G(tDahZ1P z2c+XyJsnQ9q%ZgWU|m>a(f?nsz<deIO_=XiYt2t3AHD1^(cji;N|wQ&|928zLF6zsM(NWx$B`#jpY zV47T&sf1ACO@8FH(bm+mr)(<{-L-MspGMrBI=6PcFHK$XC+3J|7Ak?cMR^DUBcjM* z4Pn|*>%gPgS$Vjx*qI`^e{*&9@+9X(Z%G)V*@BOR5axnq?0DjZ>=&YG8LW6 zI;tneS*0K1g%Qs!^oc5%DGREaDB+WRkNeD(;|uiSihB%$ zar5yb<`X3Ckm~bDf;WN)NnQyX zXO~Zh86p7n6i3E>O+lT#LMj8bfPL6ueNL@tTMd~&&ba<8n;zGuK7x}_MhE_jp7}1^ zx7x58udv#4jcLpke+2)4`jzQ^=oiGip97pj2_hGumGX!zj)cPl@w!+Wa@f)NZz8ct zxTEU_7+EsMv(jzBOaaRN0~?8 zfDe*t!A!RScdk#i;cWl?SOaC@w)UM`ebGHO8ad zz`^cf-WH>w1-Zm4vW^Umggvmh{P;(2UP$#zB=(5HoEUo;xrrcS!D+IH(1(yG${?P= zzlME-XsjEc(@ai`-T>o|vh)I)+;Ksz5Wal;={2{;_eHu6zCQqVK-Ci(E96bemjEF5 zX>STo3jElDP~r!T+lT$8NjONT=1&R1jA@Ng)&i*QS{=hl!rXUvUc&k;dF1uO4n3?J zG8Lx0UoJLdxhD}`f~ofI4|=@|*Y(uZ-$5B?Wn+=A%Trm(dTLs1?JXl}8aIO<9UGc! zoNAoMi0tMj=5o`2QWCPcI5`Is{{Yj_NV&xl0Ez~{?+G&259MCj`nY!uA&61D)zH7t zTBLWDRk1kbn`TwJEsNxv8VU~ArZv_IQl8*tj1;YNi&`XIEz7w)aboRswS9<%P_mo<_MeJpmqJIr*LEAtY--L_9LUnh;ZXf1eD%5 zD*0uL7BP}?=XF#K5u_>1K<1Y6sY1HWcUUed=Ljw*j53`}=1q%d^h|S7qU}pXL2A|1 z>#~>@Ed3`+K}?y33y(g$H44bM$gtP38o879GAA>95Y`=hh%X+|ScF5aXY*Y?O!vw- z)C#sYTds{cfRF0zqpKAY)2;olM_R4UCG3rz;m%Qnvzm%!zO-ahQZ{+f6dB|uFV1qk)XGaj?--P_=5B!1Yz(Q?{)R z2|JjL!njNxxMwhqVHfZllZAJVFyFz5KYFUEF;Mn=Rdae zmg+==>FeA5FZZ7&&d2{{inNk{-# zJiSYg(kU84Je?u=I>UZO$jy_@#CgOLHLL_S zg-C4)f*A7CX{RIZ5!{9!)W{?};2veFP_2iDB@1}rL*dbf?(+#g!&8ZnkRlQhI1?P< zmKx8^3i<J*;J$*VTdmdr2SXiN$P+= zXz8BV1+o4e2noKzIiCwp4pgorq=xQUqSQ3wEZ&rxgcPKdgM*(Z7rhcZbOe7i11wSm zzhu?qHT|sQ<%EulSIh00MtFTKyr%Gj`(F=vy{*Tb-6(-%He%W9hop2PtADyZ_m8UW zx@6K&@$u87tRju#;_DTd6*3dKO#Ns?ks4Q zP!7lPG@UXM%QS%B06!v>vBZ?1Lg;b}#iHlk2)l{qz9Ifw9VB`S8G&&h6g_Ld@_&6i z7b}?Bojom_V{^IxlXnVh@1&IeQqNC4ZL}{oHXNfew^2E;vs=D*7)i2gTJ@B zl@I;nt*cTu-Ag~SEc9~Nh!oB9tLcd;7BcINwQ|06owJz0&E_xBqg$1m#T1K;d!twX z`eoMCkFd?%ISBb}G>)Vu2gARG4*KmFc5nz%>%vobl+*cmn(kGfQ~*{?_Z#KG>M2KL+e zz`Nfu&|At@6fbt@1Xy&E2ZZ5`%O?2CDp#lDsg3CVHA^&j)ohx*%dYnknzSwP^BPcz z4zXMk%1+WYzmj=f?R@hkzOMABK>??fxRg>h8IcASQGe^QW-RHkwHGqyMRi@)WuOOG zCc4ROH98+p(oW}A#}Re-n;d)vQ7)hlQs#V;KKjqz{T=4B=Xg3yfQhC|3?U=0z3f&4 z{f(jO;XI$KVv~3!I{ui;o>Q7f zkfeE{dPiNOi6%&bQt!fA?RGeDYe4OLQ=Z;P)4A_rQ)V69)_t+z91e=|cOGIHvQBOW zdYJ52PrSPycJvPXFY@94<$q&mXW{*?$Nv?k*#7@YyToOF{*QRbCdT=L^S?{G{)uq^ zBkkg5=O*LgVgFx5M4o?MuK!2c_3xd32EhLx(yssVEdKALU2OkN+V!9Mzr{p0HdZc< z|DCk!KU&8BDJNd~zSO%gXZu-z-`?-O{kh|L z>v_w0+Iy;%6#@y&;@<=ei|mbzbjZ2kzuNnV2h7QQFKN|^>^tAY%MtbTt_>1xf7#V0ThbFff6QS;O5r$kH>W;UG-g^>tW2jeY z)Tb;J<0QS)tGicUe7S)QJMG^i7lR#egCkvrCghlDKv+9;b~>P61a3M&Z3Va1Aj>TG z3bkNf{RR_2p6(;O>3+dqqhWwVeuf+AK_dJ5hJvygaf0hY`K`Uy>}azXkpJVuDf(hO zZ!_PpMBfY|c|m==D{{`Ct#}}3MM(+wUMg$zw`u3XKH;mJC@RV(rxl;;44CasSSbrK zp8*>Oc}5;Ifg#SsZ>BWZ`#eIN9uW&La z)H;#xp7=UKI$a;pN=jW2RpL7E>bq6fy?56R*VSR24nf~Gk(YZKl`hR%u&?#m%NSeT z+dg9)Fq_t3n+?X-XS}Wm=2IFv@JYg`XNtbS6!II1d*>8+q7MshP&yDvdxme|ea1Y} zeToRWLauiJ3ttcme6z38r{1i7%tT8sUJJGw_1eFT3m$8jT;k5|A*2*`z0Ye8Q8r=_ z#UDLLYx z``1mHB8(6xrRD&Yo%rjkA-J{NF{#239UgX~J zzOGf=z@cDgWm8gJURhdIRzbs@c|f0~p(J4FqiFc!t7Rhkq2XX4*hAqD{hSfUNuyP= z5_u}Tz%X09+G**T3oHgdq)&cv5mnZLpf1e`0r?41i=ql=n_SN(EvIvw-D!Uc;!wlG zY)aQ|N_4L-(%`A(m2@1xLq*^Im3dKfgR!T2NO3)(oqe0V+uF=K z;Ji=XSI1O;J2qgJQ1Vs0!#XxH#_#lmqqA`+fzMy29(eMbW3b>6;yi zP}bb^6i^L;*i|*7MUQG?YV=+uuQOnjADZ&?y~y0OXOFf3`PUAWcTG#9?it1zP7M$? z*IBPbovgktaAI6{by@QVwdBxULj!53&g~|or`@nK_glx>IZTjVOA~8lf6VCEAv}UR|M?Ezh+STf zZis$%ol%Ej&t+nniNtv1=4CWw-{cK#9!?>L6;Xu){2}K7jzn9^GLI3z(dqHF>?nFh zQaswPXuR=&z+K+iCOyN&SIy)tD zO1a)h5vyyS3&@k?tGmSSWz*;8-xF#3*kFzx>s8F)#x;PqDo05s2SJ%wt#GQ*S50$* zIX2Ut#8Gd2{3GMgTpQ9Kh7i%_6i^z|1CU7c^H3_;S9Jkv%Hjv0pL)`VY!s;lhAdn# z$)Y|=`o*xHSOhBkJa|@-MEG-?%#pU2wZlX~#I+Vy?CA6BkkZU=e&l&5>#CS8`7L}i z{MAttkRO+Y)dG2LdaxO`9^Y-02!HLtjm^NV< zP0UyE6RT(e1k)ZHZhS@Yk|e;@S@XLC$!n@EgtB1bU?2~-g>5kgtlF(1v5J%v@{~_D zto`JmgG)PwE8&%6L~5WI`gu1jYf}x$-E-fREW+?Z0*YcKK;#B6Dst5I3Z2CQgfNY=M!PTo9Opi38Ca*!!nAnr>xh?D$1s{!+Rjy>W@q~ zd{VX`8zSD4kfXTeFun+RXk7(z4+kn>==avfl2HY>px1`;Q~0qVY)8cX0ieLM4`x9L zpf+y!Y4}jxY|fAw3Ifp_I$t*QBvES#cSQ=xG0?l>I})rzt-c_5j&U`@oB|2+f?grY z(wPUG4lE7`eq!{+r3Gq)I8oj)ZGkUd{A3L{Im`~Rf_T!k0NyBucZWhJJL^ zP!XZyU>nW@@-kt31XzgkppBz5hOdT4Nf8PhrsRK8vE@Wy_U+h-3MvEV9Lcg`Qiin%ody3~AbdX*3F4NNI#y z?E&uHHV0T}eHyQH`vICKaE(C}GLitMCr8Oc;XqZN>D3=B{dAs!6^WmZ7XkM=5f&({ z;H$;XXozT05+mwP>V2Lf!a71Y8(z1jcBmTYvf=OyItXy&0R!cR*vrtz&V&Yh@3<|g zzQlHB)V*0suQ)B4o>~IG58GF|dnYG!T9P%X{KoVU-_urW;_L%_FEYdTSDuhH!dg;a z3C=ZZVmwJn`n?tEar>@Yt9Qhn1kxt;pi=8YYSL{X4ZP93B^QK1U_7tz{Ew+@ma)!g zi5CZx;UUH*+!Q$M6ickkJ9c6ljHB)7Svmr-?hvM`;US4Wq(+FT!H-%4iMy;^&IA?b z=;BgtqM`^=tjx;AkV=46tdm1?~ zY6K}x|Dv?3e!#yX9(msyb9wXVx27DB>Cg`?U;Z1YLu7P;NB_1L>Id5PPNIJisQ5*O-5(LBoVA{$-I7C?!&%qem|6Y)!S zL(+)+ojrnePlh7}xs&2mjn)oXaGW$io}f82yJuyAYOvsWpntce{}PNd2CxU^2e~AL zlurIdHW*@C6SL0cLRk0XyBvBqQ$xQV(fj}@+ByqNgCvazKPj_coLlGb={`62?^NLL z)FYzZ+H{7HFE3Ixz{%fsToOKrwGor}Z;>xpS7dKxR6a+Ic*+_R^E@NO|9%1g*pb`I zskIlp@@F@f5PZ#}4jzO9v4DU23N7rmEyF+Ww7X)<0t}cFo|FcCsV`lH=zE$gda%e$ zY&tx^Y;W+zv0y=;Ho+*C!s>e@Xchf}(ipgLBgE?_Q8Uj1utZ0K%6)K$L2}=g38$L3 za7p7ogFS+dVw|pANQVDPKBpg)?QTRd58%n)z!70T&2-}Avvv#q)<9Mm>k8p&#T?J+ zXRMQ)u=Wja-8pDC0O>>+S7P`N3AmH~W!wnlrIc*C1q=x%QfoR0!za#=cnv;M-sN!^ z2EFjs#dbqohoFr)eth%a{R(~x*l`~4{^qTTJ0|r+ks{eD-UxILxeq5~UGC>jnjRoh z61xoPMml>LY~dE}ePlyj7^SNfg5`q$2R`JG3H1nESf|mC57f?3?{wb3dOCn#!H(eh z*r5m|4ct0)NZ6da5|!gP^FY0ID)oKvj9#b2MDNz|-9jC$>WmyG;_>ogL8?o$UZM@L zL)l}K4j&6JF~H#K2RJhDVwLNJFE}uWu7Bf&8N$OjHhE2>m+Hbdo-VhrZ{B5}b-!OE z|NDjIlE78RBoMXG%aMoN);eqe-i*1wz%(%l>##K)MSAx*BWc8*1BKXn*wTbHqjpVZ z@SHEa6?JRR%&<=qnuF#Tu5@Ml0=o|Hjjr7KdV@0*$k4D~9wAqMTZ44jA>V@b&#l(| z-9{`tyxbv9NK7YyC!!_ep?Blj{eqkawHDnG*@)YISYRghn1o*^tR*c9L%sGoeAyYb zk9tE&yf=Lp`iYoltm-$x0L0a|p~56IKn|Qc83{7GyV9SSJ5&cDcS@A{@!T+7s;<#0 zXy$e`pU_Pd#FfiE*b3B?dZFk`SDNbnH?|hMb>E0fDx>ypgZ7w}D{rE6{qSzeHuPj4 zu-F?w4eIzYr5iisjUYEl7cL7GJYMF(HYJPQNED!Hq7nX9-|*`mA~#$YhvNd`N^nef(ziGs?Pu8w z!I86WB-IJVRG8-MVB*ICMI?G-INwiBBLWJP-k9%6H?)Pf5DOz;NVxl3-1R|w zbU+2bE6gaQ+FALMO;WEf9qSc%F7^sK%Lx$`qV=Ym+YPrx0|z z&lxWY)*A@UmWTQMwUoxlX@KaL)8|D|u5*5Q&Zgu)gKDX`mV%}33@=G(*qqjyiQEh? zxTWiiW^_a3oU}B3;1ovTAuweYMTRyDGdexEA$V@jKo);4-$0gkPDC1!##K2(!II>X zCDrXDe?jVcGLM5FPd9=iYED*~okp&B;YVrK9EY?r?JI4gVuna*h!Q(!6qpe>i!B+` zu=Kq&TZtH?CCv#eqg7QbD^x*uS)fRUC3clG1yU*AK@&epf`C*o#K@8WU?iB*+K49ELg07) z0p+_HKgR}B1^_nz7eEb4Gf=@);s8jnSg|Q#0r)|ZUd(}sF$k4F2H?a)c0^(V0&+u9 zabbZ7BLEq|3BU%J&TK^&!mVk?9{^2&P|^aneX|5I5qVG;tP~(}>Ec3^2`R1j^f?8f zU*Q8J=$iJE9&a_$C2-EYcZ93ZU+FDnjvLrjB-fSy0Ki63dJCL81_~9(34tEqL2;*@ zaWuY?r;yUu^HhIxA4ssfWKM~t?UlXg@mR4>uYp@g;5H*dU{3)w++?-z+?W6K8B@ji?D{bzFG^!$k65scC=o1~1!bVt{ zO@+)22}@y+H|?hAsomN&)7q{)T}RN|CD5+Gg&w3$b6McR4$2H%YL(MY?dY={>I!3RsFP9a$l+1!bWUQEj$>JO8SOMx72#Cpnfo!HchCmQO!A@&B z(^{x3U7&n7M+;Jt&Qq2y0{)~$H{|?I%ub9=OyQcH$>6g{3n@e(Fr%am3gwkVkam)0 zlZLPzolhact^?vp?_ef~*>DH@AUI;&vhPs?Kf{Urd+wgY{mJFYy5^@{KQV7B{j$#q zKYf;$!>iHsDPR=8p!b|Rp7EE2#e4$)%jz{I{L?4k@Hye{Zx7V<&ZtLsG<(V|kq_d3 zhA;cJkgD!8oYt>E4@gI%TfQ+p(J%Hr)d6}9fBaX#KvcMKI4;^WWwxk5)JxJ6(K2bH zjIRGoQCs#8l9{4bzqq;r4L_~+i9^hsIVMNqStd8ZQr!bDh--nW$$xVQJ+K@#>c)(^Q#)-OG>?2+w}SHLEq8f1d~6Qx0hzoS2sKT%$ZZ4_+nwP|;bx~6&+oXa2Z zFC4epsoT44hTdtTHf&;co_%VV+7sxG?8WKFTKC7@7|xH&TUvgj0&-Qor57p21E8Sb&cK&fW*R>B7m%Cl(hELBd z*n+ZZsQn^wdBdCimP>Ey@5>kZmtl*O<=*PBYWJ8B<=eWGeOBU&%tDVdR$=uBtL|G? zm3dal{vrN{U)W!Vh$*kBI}JFvOb^U!-80>}4qe^ee|`RT^tFCf^~wMJ)2I2h`fmPe zjwAm(y&}B1t+;ZP6M9*U)AaiJzWz}e!uUn|uKkgOnE4?`W6x0W%zaV)yo|l{V*R}Q zQjS>uk=$Yu&h@jsfEP0TyE4ZV6p^fEO8>FP@@-=ftVGW(Fo^xMKu6Iga%&2x(8NxE zp?#UU&g*+1lTg9T2B?%Ky;U0EN7om-G1LDkEsni{#MK;ApV+ucuwM3!sWSJEpuCoK z!DNyKsF}^He0)r;tpW*eo72zsph5zP8DFC_d-hyR@O<9bxpN9+Jepdv@6&b>NY}Xp zGW}N^+6Xa9kAzEQ95vB(u7S)xL1&{@OT|o#)pw=y^<@FZ8%U7R;1S9O>p{_rs)K@4 z@kxaNVbAm^4UJx%kDpGC(!SqU1t@!Th$Jll+g&NA;H!h+HwrnkegTF|=R7?%hqmB| zug0XMe!Eq=Xv%7&;g+_jPVY~HK-UFWFR9hzq%jIwNUqbHDZTmnp>th+!fvx_>fx znxTjIj8wSM>5N7VYV|l3*z4}k88b=er5$ry$)=}m_qV@K{U6)eJ%9IeMtJK%!m__P z_m)4zd*MTBUKHKf+o9Jw2OK^xQ3nSC@^T(YrH>0 zU}a!q#Kh9mWsi2gE1J2b?C);dWo9k*YM8Jo=)jyu%-^a-B~4DIhu3H_@G#x+cJY{J$WOPHsVjm!HZZ*JtV6)%tPNv|fCkG%PQuPK6mXc@J$YSt-GsX(30 zyWsNfwL>khLbtYlH&9qdC0WpUIH=mLY;8dkr*vmJRh#m{%+<%MuSHY4x~sF&cX(m~ zkGg)#B3|OBc*bJH6?qn~Na@1>|Cl#wCGRmv!d^?)?747_;pe^bK+a2LAoQKVr^Vzu zhG)G28}F;il(l?gp@x#qR0XYkloU(xzZp8x-XB=)`sdUHw177nQ?|eHN!A?L*vJQX z&WhBnLplo;(|7j#iu^$K=omZ_8JD25Vre=Sg@bVDG2T#|mrAwu(ztXrkdEOKPrjfU zr?87Mb3xOf*qX5%+Y_vK(4Zs(oAruM$SMgb{vp@stG`v&lJa&|Tfc=WjVr?MRO{pm zv0^Sd4yPaS)>t2zPFjgMUXfWP3uChtoIkmn^X!)3_`-vVSlbi>MbIr3Gq7C>#)Mk*B()GF}5^~StEvZa4bW}s31#p8iUZnAtbbj zVcKKZh+VIyV4)|#+Lxi(eJ~drTghuC#Jal2ax;;`o~nAFKtJtf$d+);s4=T)UPtKK zp;OthytyO8_@}k0@TN{MwTh;iHp_6vv7~{Sj^25FO0!d7Qd#qWR?|zBfAtb(VNK;q z6AzYu=!AifAo`~u>!{~8bvu;!uTT2=sn2SY8p4Z;$a-zRI{=5$vcnnY_e~F2nc4u3 zi$veqzl&81vMci_gKld-3NSGH{{;lP<#bLybGJ{A?T$5uVmGhhLd_&4WCTF@MoWYK)4Q^gyA zf4vhK^S%NRFL}^5&Lthn?SzM5p2uITY5kWP{~Yitwvt)S@lbVXsdY%-@o>s{Y@!z5 z%}lZiV4thzXJuz9_XGr#rNcb-bkS8A`4W)G+g@DoW0C- zdRES)#lqTH0U~SW=*(+pq3guMt2MFUPGz(K6V~B6x@6~#sTxj0olV70NA=BK+au7w zgwn5^R6Eb?5iL9VEV44ceaFPIB~Zq3X2D{_q>zK?TOgvLNQ>(gy{ zR*{$(YZ34IR&t6k%i=|_5M`XmkJTBmgi(COMu%&B6pJo>gCGlUmr=^OEM~f_u|u|W zX*6fuo@l$NgRN6?>YgaB^1!Kb%Sw{*cF4l+TD4Tu5B047+aKs8Ec_UOWNtx zV>?dMb#x4qO8I9$>TL}A^=q)%G8un z^q2hkoGSfXCui$aBB;IC5Q+}le-EOME)6Pk_#%wDpF~&+nJ$h`Nsu-UcS86r@=U-D zd%%3;5ADBB(7at2`H-_jm24@DTH{vUpR6^72t? z6WcRGs%m>8F%b0->=juQv6erl|)GT8FavnvRGpCPiqJtCIm_GAS z`B+ZvB9%LyA4c=}RANIWo(!0&m$#^u2vH#-A)!Ey$h<+t*Zn%#?6aOi`F`tF1zfV}~wUIQ8jZeP-XlO5A ztb@ceT7~WiZ6oaAXhY}%@spa^au9}2RLo`bBd|@VU{f$AE@qyKRqxP-vNXy#zMx%D z=v03ixwr)CmNrm-{2|ukZ`PGxW`eb%oZz;gR4XAdri7s{@umA^sK$U-CPGMGNlRw} zb*8^HAchsax*9jtVg96lC1xSiH+&*y)}w2Dq^y#Vovnyv7!_q3nF-E*vzumKhOoa- z={j^k>f7iVg8$MNz^F^iT~L}YnaW?w)lBZSLLo{Op@+xF>kOt$X>5n$bpu`~Y#_y_ zGw`K8OklkkQ4swun;)+xGDPCIb`%m4Jw`wnF_utkalZ=SJ$6|_k4g=O!LJu#I>0(+ z%Im9d;YBUx9jEj79!{8w4Jsq%^T;etfI<%E5h*1)5m-GHyFwG4-4uwm{IpJp z?3qi684s9#BJPH(w=$z(Zmr~xre}xFEezB>2`GpO1PdZw&3W*+PcQ+@B*b_zJc(hw zhWbuj;g?8#UtQr*h)F@y@+vKzjaM*-7Sz9Qfi|#qy*ENDe(mZfh3-#fM-T|FbPe4# z+6joB0OPDN8e6pqJyj8x5t3om9IxAkF`a!|z~f&vQ`*DJ6R`{yV{hn2Eb#OhAuWZl z+3}W}6MR1!(k_bc zZ`S6ndUM%lc*1gYu7yGdli4~N0?oBFy(Z&!bPT5y05`eK$5i`t-T2w9btU&tQ*Cox zlcs0+X-g&tFYDu~6WR$&CKs>sqbePlyO%scr3M99(hZg&7@J%C(=MeLt>gq0I&2d> zHisDe5G8rihvlQ^9xgT3BzWt}t1A7@RB}gv~`n>eh;MR~e=(AubnOH{d>NX`2YbhA3?R zR&*(lLPqCv;2^s6+!~Q-+jsR20i*g+AZB@gEwx%Nk)!(DrNOLQEas?huJ$B`!;fmt{06j~o*y&HDpeQWvKDT*Ewc@p0LQQ|Ts~p3@GE#-@p)M803w@*)-Tav z9l;d?s*J4~9q&$BFukmeD5cM}5~E4XgJp*{dn9-^QId23IW;GBOL^GcKALt4mNb!= z2h!=$9@rqB5x-c1lE8Nf>m5fIs$v$y>HhneWiD{$o0EH=*s;{aO_7uxOr9T)iPck| z#%zTIN}9;28Lv&#jz`WlihN8c@%mbc8(AyLAAe0MW{<5N4&?n_xD^VNr6znwRuhpe zADq**suu>#lFbWMO@78&XLEY$^!Ak(nKz}FTVgw@QK^?6WV8g*0-%%bFFcdX`On~{M{iLW>=WT6C5g~ByZ=TUdObLgK{$}+2N=AD*o1t?LMC34xr%TL)YUiwabg|Uvc$s}CNA0#BRQ`wy3WB&YBw01Z_n3tpz1{UMoUe5Jl|IBrZega{s;=YSyH*9vzPvjx8+p zCp?)ixe|^e;PgRMc@?pGrlQT!g;W}|wL~G9g?$O!-T%SZIR;nu_G>yeJ9av@ZQJhH zwr$%+$9B@OZFP(t+jb`Zx8}^5cg~rq`Lya;yY{YH>-n&1|JHTimsiv**2Z<}Jrj;^ zmpFw#PL_pPiyC_c3^6FJ+<%cHO|Cj0UU{0u zrf*?#A~&5Z!P`M{liMt$3S|n_9kaD7dCAj!bf0@SKv}Z?{iqSEP8c~k*Ym=tu=%!K6(IjOUD&<^~piH!FS|G#>CmhDgl4tu; zg+Qq&o;cW2ajg4cRz6wNm+V*79(}pdvz_oS`@M0!o?$Gzhn_Ke-W+}1{uutc(q+1Y zTjp~dt2T3(;_{(vK>*n(i0R$sG%CQPDDKEO>>85N{U2N-2${9+)O0V6v!FlAlKi4Mqu;9*JflM8(ZNO1@iQ6xHyvM+hOzt+Zzf1QTCt7D>%@*5ffmsQlJ z^Nd~DSXEAzWk)mRxMXOU% z9~b(H!L{D&RGX^r7ux?8Yc`##x74;KE3qbh@tR!*lN1>Ce7)p-edSH>^FEy)eb;YK z=a35k5kmg~MYLHk1(Wjk>8F!1rEM=TGwIy0=-ZzXJzH)k^V{%*xbp+s&ZN_7+mAHU zjoilMgB9R57`u&08+tPn1%8jar@M^kym7pw<^TYx#hwkp_~e)}`*)|go^}~tgsw01 zxU!}`5y|NK9u(w0KmR!ZiX_mTYcwd{CC~;Hc$L;T(VTM{GK9{%OMh0=Z8NP7zJgfm zc6``PnQ6ZG1bQ>-I5%tXo!xOF!|a_=LXtAa{<=2XeaUYW1{7NGAR=Yq&%}L>w)h9s zVsTCEl;v~Rhuuv0biXS~5zh9byW`~=E&>ESm0{p|@yh~iH6EIi-Y=BYus?n_8{<+E z{<`*Q%|%6Kcj(nE?+)JY^%=lx>F08Xxb$D&5z_$eqJSe9z-mR;Lhp~<(M9d?dgIBVL-7AQ!gX(Ai?tuclLv2 z?8rdbj@xJEh_K2g<*It2ynKf9z&pHl9K1E=H8(gcC=f%wun{l52G` z9l57W(jsqWk++6n{VR`jW@%M1qOPiz97jzJpNfhB4g-7p;nBvq%4e5KzHl)vAusJx zLc)E{RykzNgni#mQY}`kM77Tpa0IoFBK~)7cD0ozb7K~7(NhRNh`J)@+cHWBLsq(O zdPX1#mW9#G* zQ`Z@xCCovFr8s}#!c~lu{e+b6SlssIrjLS7gwilMM%~VDQ!< zIlXX@3tSPu3k=V-WS5A=JeuZ?MJ$y_lz0=v+>=dCv858Q$ltYqIY=Yi&ibn2b)*>6 z-nUSv5rfuCwOyte#EPvMpj^cx)zlnp!eL{ysECj(DZz&#+LF-UP}W+C!<>sW53eEjMLNaeQv6xTuAFk4C_o+!&cFr^|bB2Cjbn5qVB5op;StS%;2qIlQb3v6m z#xWD8l+qvr)<*LyKMW?3pYB@=)-mX!CUj@Eg5Nvd;1w@8*&QKYf{0fIB9ap>O;8U^ zc%8FiCbU1i&>O2SO|*nPTv+K~6@P;&z8a9l<}R$RoLO|%5!&K1ce#D z=`;w%Rpw2XU5nBB2E930bN`A5aCJ2@?i+W+Il||#5^!Y`7TIqZ>8~hNe#UXkYfbF9tjZX8z&NC=2j#}XM8b%J{^b4 z-jHk#MfAc+n~wkH!6=~-n*%PCXytZYm3`KnWP(F9!foxYqSJKhW?z89f%$Liv;Jhu zG-;U4r(Q&)?(A&h?`IXd46~0uNvvM7d&<;|0~PW!cO@K;A#CiuM3yxO8FsbhC%HK) z#X8-xls*rP^5;m31xckbM z;eki}l&UBk6gvaHpklu2>;l0F10P#l0nkdWjoL^~6V7|xbQur?LAD%4Ke1=>IETqI z-;w>Yu|rv;F6G`bQsSs6{KHxC=1&@4+nB!)k_yGzl4GJBQ=>b6URKFHC?mAO+3>nD zn{kQ68W7HOv70P{yTD-~KA|c2Sq$^)ih6JL80uANkIsnbwoNr)lJUpcSxTkCUJ6@u z*)m@XYm-lANQA(ck1Cg2Gx^pE62>xeZ{T`JVrz}Dg2j+=NsZAOi;JsJ_H%Im=2oP~ z$++G_#!0#WYib1ji0o91qm2LbXUBS6r14WUXU+&Ck?Y0fv9~|5wy>MevpM>o?>#ku z8?@xql%}@m6NR0Xvi}3gL3(z@LkD7QRt-|Ae;_&nRmWvg5ZhZ|q}@3kU$$2#7rq=( zMTf7-!sVF&mV4UpJFvvGu$zEtuQ#rs?c&~_qA+TS^n(I z+()NVSMCfg*AvxG1p!0#;nNnef**TZ&OVU=&47w7d)dX>9E$eXqN($;Y=avE7`|$p zz%?ILzTX#x(%I-?@c2=b7Zs7Jgs1s{HmYCo;5vAvn6#oFOJyEzr7$8UUl-_`qcym= zsiRRVbhJhkAMpJ)0x59?OoZGhG?r3PJq;ZtzZ?q%*!PSn_isdO;HY}J&4s}@6o$qx za@2=Mh3ttanIqqc;#+I}y%4g5tuu#!Dcmmfvoz~8W%P9EYe^4SqhuA*4q}l!Evtxs zr2?O@f^iUfR}LO<*#Bjb_7`}WO@uW(!48bF7+3<&+A_a&8$c(L;_4GEx8Ms`;>GqG zL8)j}2F5y;%tOm_c6)Hds%}_00W;c(@)ugp-i>>8;HCBi$XcwCa2PMnCNUrQ3;z9d zjtWCx1Y;4@&SyQ^934ycczv^EReO(KhVu=ugC}KDXkOF&Vk?VEFTzjvf-Y7y=--Nd z4t(f}1o^DQ{O?W;NIc{1pHv79xA}Js4zsiyaMH$rk)xl%#j~^%Be#^thq+?zU_1@Y z8UWbMTXOx}bE)8uIvID2w;koBNE^B1_+r5>Yf72ajJ^sE7`YvkIvDyu#T9rP>l|sI z5YuBL7}UIaft#ccFh{Id01(_)g1=V+@4%z-)Z;zNGx9zZ>kngzhs}mFu`3TuwIJ0$ zK`L$pVK$O)n?L(*;>{6_H&c&Yp?l>kiJe+Tt7{JK!T`L1Zb;|FrF z0l7WIg?z*?f$4#H$zL!dRU+I-!wqcgj) zgBzkx@XU{3N3bXr03|hE*O9?9kW>i&?nbQ?i@OULEgkTF*lv>)Q1PmUK8p-c@c}7N z@q>gu3juWUC$xY!7JR~&H}v>gv%)wpBpwBz@x}Xi8&zSXR0tS=$hwa!Lt-b)bSen{ zf@EnN!jSNV&`-3K7n?KnflcNp--}vxFWP)|jvM0R4BI z>bF`w(jDVu2g4VvH`VovPq19o7wUxRBp`0)$$)EZgUyyGT9^R@?h}89JY6rc4v8>y z9Se7#3?WC@9perX>9y!qk1p8&G}TWOc;b#yKga)IhQSYNhcH!D>E+VhNY2}fvKP(*(TZgl5TkOw~qS(vB2kC$y@J$aFK=St=Dcw?Wv|^VDWA?uP z@c7v|zzZ~iwE>Ap^d1iK#hV^9D-zHNY!I9|n1uK{8;p*}A=i)(BXZ6*SUgaH0i*$m z#eC#(Kri0hiGqSOUb^=xBuE?Uyr4I18!9lbHnaozeM9^jv;P{!gByOQ{|+fQSVm*= zH}J=lu=&J~8}L{849Lg~zY^c@*F7(Nth<(DGZQr7Bb0jZ@mr8XX1kGYOe3f`0k*ra zDPe+%v>kkgnt1-;1Nr=nDL?OH(3dP>g6k_p9|51XPOu4$k=I(RSAl2Lr`J6D7JEc( zvU6Ndgo|G7PvYb^uYC3Ai&+b`FCri}@^chje@P+Im5}B7FDi+>r+huJ4%#Hd9JI?Y z;2oQyIVTPP*S0_odn!5N2f9OLk~l-$+1$&?hO-=4K!?+@+##sF42Xu_*rn8; z@0SPYr{s;wj_JY|NX`6{WMtO1${SlmyxbWVHeueTt26{^bZ}v&s7!+x8w)3-m{`Awz88SdA%6w2qlnk0?#I+Rs7Pw76<|+Bn zmIHLng}rWJmK4JYd7vzZXOxwqpM@jRSYm~BVF-j{z0v226ow?A&2htRlFlV5J#2^ zTStW@v?6B=M)e&=9wefgkHhjr^qx^sXP*W6kZH_=sEx7HMS&0MMW0bLjNNwclqo-7 zfM(pLo}S0W1Ji3l(;k@C&c%H{m)I z--|L5GJf#Y=sY9e8Z41luE23Hyau2DOl2LeiMKYqi^lSJF8Q|O&RD*dv2A*wOUiRq z(b=t&0oQBa%Xo-+DW6bBJ;u^?aXj%TgBZ$e_r=f(A(n|F{kR#^DL_}lpCRl~_!+;S zD!B4jPnWs8d5=5i))iRQu9-fM8svcx@j#(UIy7tuMHLd+fC`P9QFqLva4V<*XFuE0 z71*>N$Xkwobrk?QeZ+16(+6kX3}=E~*j#8Ol!3s2Qi#0Y`J1qprqHkIK*`_#8r0w* z&?;Jq@qWYWx8))JKxk*R41I$Lo|?a7vqjLRPO%ee)eV#?_aV_9n@9-b?xX%ftq}ms z4buk*wZTRzs5=_V6YA&%3f~siNjx$YLE#{k7Mj<7D;Pcb3K~eYAvo`yW4iU(De`fQ zdjo($>M+kPaj`-0M;+`F?!#0Nn8sY9i%6NuBcgc|>PeYOM26Exk5Mv;M8tAN%YI;) z5E0888%IPFBGhjj(R@S~f3sG!sh=6ec6IkIsojI~M;e})#qy2!%QQZb#ibgr9MXPc z^GP(kee;DhU3tY`zuLo!KWMsgik+JlOh8}6}FZOu;DQf*C6&{O|3HpLXv z(%6)o!;Fs zpf*jvC565rV$0L}5(l4y27kr9K&2Xm864{F-6(kOdT)08zu^Fgrk&tL`BpYf#6nGX>7@N475<*z(QL~UFEEtA4XevL@}1kQKr3}i@Yeo zIXs>vSOttb5WX*1Uu2e;vT?lM(=acT_C%GHb^oXoBnj zCKa6$pkK_0$#Tx+ktkHJJo$WN28YrjMAxEuuIBcORy|fTb$af-)xo5=+qyREsL_ad zlS|pox}>FmA!I|8#W<0+Yn1<4$s%GJ>5Qz)EpY(WQS%O+>hvt+eGDaJH4m_=nO0p< zn}%^{B2)7Uic!=uDSb`DBKQZh+=)pJ=kX4vUdGHuY`58A6SsD^?XLnN5U z=~tpUGOek7bgs#Hwt?aOvv;n{v^fK~^l%I{BKCo!yeYc6n&mi5>Pj$l2VNJR+r~$Z z53SP#?Q-q&Nxzxl*NP*Gq@UvrZ-Ybqvbqkw7u%!Z`Nv9L6h^4gObLfASwK&x4B3WR zq4Vjm(-z693NsVDv;RiTo_oi&Rv0g z4Gnv{vUqv74x7#ke=TRTEgVO3tb0!!@%f?XXrf{pD>h<1=t4kL>5W4>7>KWg17=ao zQVh*@%?(z3xINW2dv+vBYJutpzhG44L5o&OVt4$Vd-RV@ln~8)p3y>}JCosgA-WD3 zq*^zONM+rV33`V!_3C*O2oN87uSjovv-T6uJB&8n9#y)=SD%KAdObSx(b%@cN=w6u z3QHvjfby#M%aluf*6HHoMmv$OufU|F+Ol-^PL05HQNN62N40CzqNCmD_=Kv|V%JYn z>&27#g=jJ*NoY8k6I>S-(ZGn;`YyaeuHddz=iG7wLk!!>*cL~T*)^wm2!6@!NzwyT zt>iqf3Li>Sl{St{*hot!ywg`tSw}ThaIqAX$V&n3g`bGs#0FV8r@J~759R0~q;WIc z`hvf{9ceozQX#in@%{Cz)YSZ-f5_maM?&xkQ= zEebtQbVM^@R3lcT2NGL;M~SX;cBa@7eCt0a5xp$UM3>anYSI_?->SMdY?PPcOqU0G zR$iVB4O9;nrM=kG97j81^Bdot%zYwvnmJhU=iR%&U9lZi3!&?T9km?YnASp#qex@q zg_#La71tGt=*89*v=w^q-UC3K8U_;1wrm+t4{X&b0tuCZvV~Z~e-*ONviRk2GUcy| z_3LPGeI=%$!*=)43>_h4+57=}Xn=ibn0MHlC0xzOHCAG_Yg}DuK8B1C!y(dM`nA%?SQ zMOuWd=ajlW7DqRMyHFCSk-1ufVN3HMw}9&LW2^yl?Gp(P9L@{zbxcMDNYY~9F8PVF z8HflrFy`|PmfLLc7y@J}jFp zcqu-rHH2cEV)8`2a6&j!Abkm3rAs!zd^Wd4tHswN5ZREa#4CLzLx!Yje!Kt*PrUg@ z%S4Opujj@C`kv;4uB$%)RX-^`ogEvfk|TQSN=+es-KXe$`OB9x(~g6}m&Q(=mMSf` zspXr@f zH`y}jW}r@aS8n&6ksr-clPpjyXDw&QW59~?^Jrnh4fhcR%2$21VZvKYO>m9oHhcPaSrCXrIg+)3z(@PghHS zn044(I4Dk$#*o=!;+WOUDz1jaZ!j!~4|NRY0$Y%%5y`4M&djV*`xk#>^^@1|Lh-ZPA;sW|+WQWWj5gNgiiU z>Wx3@s;1hU_INA%E3ArAeZxNFLl`FSxS zRPofd5Ope*SUE96(CxOD)l$vndNFti?a_S>U97y0y@Z#ElYL4m4S6J+y|KbnZ!$kv zMRS#^qvghtIhfaU?KGMBH+R+tF#|?wL1);iwxReE(JB4snyukkR7xcuSsa5#1>LzK=_v#cM=8$;+v$EDactP}y!&)GSVoA_cg0gnL+m+4Ud#INo0w-7m zN=Zz$Km`V|UQXWyq&lj@^j2oMdkGC^+@pH&D4G*Ax2Pz37Z(uis9VEmQZj6Pl3|+D zTS?o^!_xD<@fi9T5L2IZTZ&rp>)O3wEUU?Xlt_K42yzY9NL~GJtFkp&m3n$oBaWyp zcV*Xxjbg!`FG#gLEJPe@1GVB-_BC^aWeU&8U6cqfd(2)aN5Ro&&>M;=7@9pqEc12t zO}K6?H}3pd5_qXS$36+!^xsmIl47#SiM`MfdR*hOw|rB_&ra1!<=v&0IuLH!&T=)D$;5L{Dyzoe48 z+BqiqxiuN$I}t*vC#S8MRLOMNHRV=Co)_c zce`cI@}}K8lAk_1&*B!FX>wAFD2H$})jfG$A&84)NH8VtvLt#o{9oG*7dJWoT_9@PB^B63AS3lwev~!XK{bYNF zLz+pcMDkVTMkSvG>ZUCLnhOxxhqbjAX{u6sI|-wzvgKzjbfl@lnu>E{8+|dtKQ?_u z^a+;ydb&sOlWneQ=K|UHNOAZfg!6K7W>Itzo(TF!Aa&)l42a=WL9Sr~J51+Dp`bRD z3{}!10ipH8VsCOAJv2@$z)DA>+Jv@z`1nqHcAf?UMcsKipEqr?cEk9ZvpQ^ZcA5w5BO}^-&{4 zIhHE7|j5dm&jqgJW= z8b<09%h3a$tINa|_1pQuL&$@&a#q@;o}O0MdxsAHGyI&3O9 zbMq|TNKcWjk>2nyKf+6Ivep8Jh&Oek@-w~u?jdxs2w?`sCeOO$PuB!h?s+doj`R`N8$h~<}Ai1n@40`)!^(}TBy!}>l#8NYvc_57Xlo< zRH_UP@+VT2krvaiPTPT@@LWaodB_}tSDQK82!Omn9sBzpI`3uk#OF19#SbYZ%e$6% zFx~ppm&y%Jb2B?Fyf8mhR8y91X za27T#bmh-cSX-RznV;fHxDZ2~$F=PoWlgKXI{fN#Xz+(ab+z2>VGc~IQXCqA z@RJ_(F0K!+)$+zNGUx}0w|3%X^AI4qK+u!|w){yf=2^5iNTKBJS=456p6{KlOyznl zx_Yg+J7NOb7bb}(qX10cfrXOF_9s>mfk~Ew%Q6_LL$rDdN-wSct@LC(8-Jm#TX<0k_bM}#6tUiT7IU)X_^_yDz}Y|b+g~pH$?c{rFKcB?yM;>1y2`|RKJbc)u`Z=X z6Z7v+`$X@~9=>P+Fv_(ZnbPgj{Gg`uE!q%o; zjPJI1OZjP7nTmQS=4fgSVDk8WtdH$;S{=W6ldNlIM?r25cqbD-Io;#+g>gj9*^pQn z<;C}}T-E3FIyz=s?LO+u4-DV}$0q=FoD6g!xn*QoMZSzu?>}Er5?uBwOB7o(7WINe zAi5@PhKA`D>j>&)eNq%P3HHdPoyugp%aa-sqf=y1{UYIYowToG-iX-Z)N@}SrxR(E zRIoi@PTFX`EA@6*PJxv=$C}=+*}|6V(vdq?-Rn|=UtT0-HeF(Km^m;-lhYQX>WEXQ zN+Vu!9pu8XO|F}6UbFTLAslC_Sw3@WMDx@Njaj&3D@7UD5H3*uX-v(~-leJ%?LNkP ztCR*7$l~~NEGk)X{70$#fks6$z3%!R1MeWB5yS_1s9uY3-1fcEkw6})YmN1hKJ^Gs zv&&m`s6WF-8V}Lt6u^2>B5oSpb3?9N7VfbUmO||n|3RABoGBAWo;1Tl;^`iBG#g69YYcP=;+`;b;DmS+ znSxN@hJ~has`i=RCl#yM7W704*H_oHlnW0dV@i>8e^+rI0id~QT|<>RmK7l?$h=zf;4{$ z*6b>)?KHS!;C%6@XZsOU8 z_rnjOo_xRN-EDaFnp-`-sN8KS#n(S$hk+5NKcDv{9?|3Sm0ikU6&bS9 z<4@_w=00P2z;-VN7T(`bAHsPlvQEs7f*0#~QSdB1%fiAqQMN)86qT6HwG0DO=M8GX zL%`YEv5u<$C?KccA(5U;ylD{rHHJ%awRo1Ik7iTjTg(I*UlUyw@w8N}sH1f>XRI!| zV*ff37+pcrr7Q-MQ_#a`1at9@jVs+v8f&;T1pZE)ijXFapxHpQD%N7G9laMSN+9~_ zg-BkT?jw5TvL2~^FtbzQ!E7T*O%v3jW_Qy5dL&)rd-W!*SN?GxIpMZhcjQl59{5(j zwiC&Vj>CX;wAIu7b#!-ICQ~ag?OcfGAVBxtF_>letAQy)zFS9y3NMr-Q49u(R|6?` zgN_RoqU3uFC&bj`)zJ9y9Vwa!iE`e%?mOtm@m4;l%PTg1(4D_8ydvu6L5y)1Y8!QXx%f0jo$u@&p1$Wysh(`{|x;uT>N zFsVu%kFU#%M@p>Bf^}*Y4f;X_8-LxBBk(!4`on3Fc%lFD>dp7%2l}>%gtImUkVtX_HDX}`1QAmviyK)U3Yh_h54k#<5xLiEfE_A;cS_u7A+r=} zhU}2}T=~9p$nZ0lN$GI<&Rn2ESKr!dIAXnxc{z zfMD*yPpA9vVk>$DVwc-gFbz43GQSYAITit_SCVbEw+ z>8x?*SGF4a>YQ!hUal4e5}z#-TtI)hUrbt=wk5THIj=q)@m+r$xS_nn@^Z83b{P#2 zw%GYSEH-l0T4c5coKEokO|v*(P6>d0?MFr#D-x<2n>D${YKh{~X`d4F$uUo_dv)9?)uPx>#Jc_7d_CVUcF)|p7He%zSlQ6Ho?_^O9k7tL zA~pT{zYc1k7MTj#%_JQX_Z5GY5gu#4`tE73Ha(WD)Nvy|zI|3*h9>objm|gEkH4n? zGAwHi=e@%p${`H}Lx^@8FX!Vq^F0%E@Vqc9xK6Qxl zrTC6)pF^!K`%iB76IbtF57aW~xe2Ocx@ooQ_TS@dI#v8PTNQc*M9cOjT;D5+%tU9Y z~N0@=>|68RcrT(8?>5Lp=|E|)a{r;VQb*29+ z&A`b1-=rBB+5aug@Xzvpr5PAGznjzlTcg&0O*61Eu>D(_;r~!-G5)juKhg}$ob0Us zPp8)Z>|1wob~G`tfpO3N+Xd;aJ+uhH<8-yT<(2fuytyM$txGz!xY@IwM!Laz?2q-B z<4D(DAUxaD_AK0>vqTvi;h5|&lFV)}k|7~9Ew~UiZMuL^+0rS$(@`wR1lf+)=a)zK zSJKC&huLLUA-CCdHmCBE80OC+;SQv@@7iXw1EQOw*p6)@Q^5EZD~pdn6q4>ni$&1a zm{zPGIF_G)M2T*v>Dc%Tzg?(R!xOSnTUu4CGh&7Y0- zl*Y%ov&lb=kqC1-oex53v7)vD%-|`ZG9IfmHkYOIdg}3i9-O3fX)P7$>xRXDAsN4_ zKh$WGbO9iqp=y71`35C_Mr-Re+RkMrAOd_KkLmN>;e{f-kRkzr!(TGu6LX$rS9H#3 zYhkv6GX;P`aC7!L&||)PBu~_b!lPN(WBB{89r<^qRjHzbIAYEQLYCWy(bZ>R|DPGY z+S9c04N#x;*~ojNBPh3gu>dB+XvDE830l6&Jzw~?ul@mIJts60UL}e7jm2L0U6eek z%LslfKleZc%{glp$SKjyGROy^4~&9hb1d`2A59?DB9()GsapSl@nHyC@@*_ax*_wq zE?YK1)FIdi;LMRdH$psnQi|48qb=afnLamy>qP!3urcRe`{`qg?(}CMrP|OFcAKdQ zMf1?nIb<}wh_ho3-)b?c0y^#Iyc~N zN81eTMs#%`Z?_Vq@ z;?f4?T0vml;Ju6~|744^JYy>3E??IzFVQ0Wigb{-PP~`6+<0WP_OMdqe~%2Mo{58+BjJgO|0a#g z-!qq({E}a$OZC$jC%~QJ49FEC?-TM3mJ29-VSG2>oDtY+RJycaj4Sbr_64zU#E|`f z<3+?j#W)tdm%e9ur7Y6@!S9Dqu0C5kXE%$Z0eP-|4El@<@mpiF|K+azXgXtaah0*K ztJ=kLqUo?)HU|E|rI~e6HAUGF?I3A_Eaf}ufrf5uVp>!hEIignlDA;Vgzb#oEL9#q z0hT*J(M6`QzITQAbPv0u@8bg@3F-B-&`n!RzK5W}a;B#g03hBvLKo0ovFhVd1;O|Sj*bhncW?js#>uG7S> zp(FdiR@lg|22Zj?z1VC@$PIgWbrB#%Lu_e&aXtf6bJ7AqeF7i9LvB-7)urq$;#mdI zT#WO4Eh>F&w5%BOda-(ZR9V0vF#*@&mjB(E;0AH~kvrf)LEw_`bljpYSQu>e=t`%( zadmb>1NNqUesvG_YNYeKyGH-0fNow&(8%wU`}z!I*A6u=uwAw_Yg5Lu28!|{Cp+wl zs2UvWQ}Y>0EwvAvm?bTpgjVy{;nhD~SwR4zO~Dn91A#z9)x{)f9*?GqEtF%J*}Si7 zDg2Wh<9y$P)`sYK##g!fC-1Y$xsEZ|;#Vtl)i|%dJD3zndWsa+o2UJ7x*|O|c?wCV zrABFQC{Mb52ZiW#QO&uNEAfSooIcUM8p0I?YftiWoVn(eZrO{zlBLxgLn~=DroB$o zE?pVr4+@~PUxAe%I8`y88jX=BT#US#ReAPp0XmOYst{RgPl^3ON&%yYyiioMi0t>e z>eka?HNRlDXf@Vx?r}bvy}ZK2TxnOhk)keilouMCl9Q3GHCowMwtgKV1DdOy!px{& zR89W|XPK&)76o0E<3jCPX+j!4XFjgxkVhk}=rR{N#Sdt!%9|_;FlnFh>_8sT9XgVv z87Btkkw{3|#4AKTdC3hTt&!@Y4Z<;QvIi%mml}IuKEOM$%#7Z0jG~z9%1jdT&q_=e z|2DL5Vf_p#^7!LMyScs~%7xJ&tlY1+5f^k&mIs@Ps4rJ@p$>_m`e+rHLedksuRiO| zIi~J!pwA6)fRxwNLJs8%16P6K!N4k-i+VzUjg>Kn#j(e^js~Qh1)ILPS{oU7l@@}% z)6Er#KU#AJSX`Fg0(EgtG(*b|?WSYUQX|}$pREo2p`rwBFJAo&$0+VzhPVcSt>Ep8 zLGtS6^57;qMt`BbM4H)HPp}9noxf_4(ZKK``b)=as!zM#PDouLtcFYo{3>*f+aeY+ z@p_`YED=@H{jQr(`}FK4=nwecWrTk!)7ONZ&;z7V`=dn4c;`h$Du%*XxLkUuP+)?4 zf~}Y&(~?6_b#(3zhW;+j!(VsAd|e_$ad%*95MXe4k(8b1lN=m>d z2?Ax5+2;ffjcI?Bn>@}#nUYYKn_P@o^?IUm!SM4xl`h9gAz9D^Eri&Ba?_grL5Wd0OCM!Pqnd}rFlW3Ttw(snN+FmYhA;;3Z&;uM0oSKGeXBLkkN*OFfR?=O z0BQj5?HmvLkM;3`zhLVYlwuN{{}n}GDVT*4*-9<40Ow%r~io;4^x(Wdv#Pg;H3T= z4MQJx-%fBD)~yip6KXS#ANvIC1mqWDI1m?*jem2z9S8?FVtXF7csMmdTdp7QIE4LG zcx$GY`fgrtM_1@&+C=_)mY4%jo#=iPa9sY-7n;1H0B6)oUjG#c6lm`ZNNE|e39RLB z%oq0UyE$hJsqGH2U6nxIOW`Mw%f$T)|Ck>=K<^ANqZ5jABG)}4A@8>4jS(856{HlR zFW8yfz*|xK5%Fer(qK6pG#)2&5Ml7}%=<|GJwFU}ro9mH?lx z#}42vC;n}(#7>x5xK_2@w~?S89MZ8+g+7t%tUmJ1s6;ves?)^ZNG6P$BToe(@91@l z!eyCnIGTO3C?>q@!KdFzlZ+0$wPVmGkf(gzPRD&&iQ3+~-n^+`F94b%F(2g2_Kcuu zq0~DDD#?t!IuXGaV)C>OgwclT=m=WAlr6+_V~qcY@n3v3BIipV+rto#Yv1rZM5Mdv zO;`=4pI5fMOgtbb+(3vx_{et{z@E>>6jy+Fbyy9eLjYuJbeuptaGiHkG+rnAJcPgG zBsZ9QatCzo7vDA?;}vLc9%ndXD*B#ZA%X|q^$+mB#Th`S ze<1hOY)dKFcj#yF>B5GniI)>GgYCj@To9>>8AaYbm`di{fBGU~Wm$A0g<14VWMM*X zL?*7fBXZf68a;>WctZ@^d=d_lIpc=jFm*>tw1NAQN0&MV+a}A3-x)9L>CG`Z7!zZ` zw%H9bl1Yp-JlBTX74NCNtL{K)%8XP$Gc$-yA&nIB|3txYd#;@0;Yy8`A({y{8pZuf z5(`-Xh~*b3f@2YVZ?8hpksZb`&^LyT{^%kyoRxR#!?z2qr^mVULb68f{lN9^RcRGt z0DqrDCpmJQ^QCj!C+=1A7rdty|Lq$kxP|a%I^Q%mtb4$_A10Y7eU8k%8+Of)?nOWdXn+GeJ3PKI592X9iK1D{_N%(W!odW96Qu& z((0{x0T0?|BNL7|(zN!AmeKP#S?vA$rZ<3Ltv0H=9sA zU-IFby>+7N&zQV~!;)&y$mUl%68v=dQfW2;jP4kjq}s5{HKHxRwkd|$2tRrRbp8iz zZy8f(__cd(+}+)wxVzh?xVyW%Q>;j_jcnYZIK|y5P-Np;+@ZKjaX9^-_slydlT0#` z%p|`L>*M_-E9-u;?sZ-3k|DHpsHn#YY>_MnHBM(p-(!mG*WhiPkoP1bmgkKQnBT>5LfN>$hLl{nY52! z6icJEU9TF#o?a}E&L6 zrct1T1Z=~r5n%9$v657RKMCK_ zLN%3;*`l9}W+-S!g)tA_5iJK&{MbX##i8ucO1RtaIlciNJuy|GasM1GUWazqJ$fE> z%!;*P8zU``Ifn{4OEh(e+R>ZQ5WxH-4u1tMVCdaAKS=670Qg{90enbrN7&|EgD{6P z9(`7U#Kt28g{M{=^rL1@8i7!u?$YYO(pUF8TBr$e-_hV`CaWkl?gfJWCcFXjdK%HA zJ<>ab9ztPnXmKdJ2rpqsT4CI$tH5_t4xKHOw+A_nkZyvDE`r@=fP>n>*E#`&_cwO4 zJ^Iv7XL7e41pVwG5%>UuezD|7ehK`d@khz%736*j+%V@;bOm)H>5(0 z8Tuk*uO^I+$MJrQT7(ck#K@=8EAkOZ1hh{mPQ@`H#4Y_VN(g5#EYK`~ROs~R%Ru(! z=^nE>w`sV`jGMeI_7{swgtuby5F}0+afe-UInDO1V$283WeCMADPe|Zhq&ZB1(nJZ zW=ojU9}~%@tN99qnWv8f{RTXJHM1_tbaRnYEg_wIQ(?8ur5e4cCB^PvQguOhnxqYoQ9tAl=*+^3fhL2qF&umjaw&5CkG5oaHXElo^lyhQ&+61WW~eA_Q|&TgsS4*hW~w za);4|$q~kIb4@@5fxYJYj=)}veMMle*}f<6eG*~|dW{2zaNRJ{6mZ;N0L5(fS!gIY zZ+wAbR{Jo(P1}7@;HLGyE9f;1{FCFx7Wh605eB`2!EHqTabR(dn=ioN5r`|1e+rnN z&_55nMChLe-r~4%1O^X5m_gkW5Jga~`F;kd8vdfeBn55#V1SR4%T*&*C(yTsN>ZiQFF1 z;Bb)0Fr*kHG64An5*dVqgI<%s6dX4Ing?zV3YrHl4-6V#ZVv()UoH;>8U(^8F`71R z4-%R-uEqkeAz?=rIESzU3??CbBByyF?8pb760VFxT0lm>AiqIILy$C3eLX_c|9k2z zBZkB?|9>S?H1ofZ70&#>q5Xt|3X>NjU_1zu8zaD(vbL~t9HFO_(r0!-g^7*i&O!35 zu<~5Xsn~)UF9V%k1**ZCqXBu)hKWzT0c^4+p?O-VC&#^nPOlTDCq3lAq%&)%qtOr+ zs|b(dAi+{@L4>DRsV6nG+aKY88E5A}g%_m7QdpD`OU`tl$(bm&q^#*#nJGQw#MD`F zRAPaT$6a|;XaSFRuGOqQt1#rnWKfX_l;y_Lth6gCa-W$86n%|-mQF5TAv zOUv@Hvc$zIJsZK}9c#%{elDg?i^XN4Za(6`qcX7J!joi5wwr}wdc6~*z%yaOuKZj$ zARYN-Miea~4*9UK3oarYS$MKp-MlmlpJ_rX^N5!Q4?erHTuLr7-DFyr1Q}zIW+ca|=0I-JD06aJ%=CBmd+I>eoz@uV{Eb z%XW3Ox}{wGvtl#s4v3h7<%i<5Uc)wTpz*}Zv!*q#xtW3$hU}Swr7mANl||)-7@7V_ z%7SHvxOr~vnN&2caq$=`2#b8l%PTFlNK1DS@uCpU@hIUD&OIei)n-+PQnW-QhxW8c zi*_mT646%sP50#N857m6IePwL;$di9OEU#a48drvs}2Qett+B*MWuW2CwttPiRBuR(Jw47_nq4qqsx93mW~wdQ z{UK?{9?gv4j3RON-QuCpnKPQXqCIeC5z1nz5G|K;Q_zkX)}07X_-JqK*mJF7S;)>1 zaaZH{5ub@qvmqunUdyS_LXMKxbB1_kX5xg`Ua~*YmmtQ~C_Q zp%R6u%#c)oEd?G*#ZhTdRP2-1L~+_hnJZsLtYGt8ll`pm9f7w7XI$@v(sP`U9V2&z zU3pP_?4qP2>foIu^Aj3txQ@l!NJ*mY%vO?$Y$|>_ zP?m|6B{CNApJ{_sIDJv66;oLA1g(KhDE>it>0`y!+~NO9{~Y9{!UmEE&lv%X2+J7( ziikX95unlp=jOO=ZDaFf$8R6eNnzE6}$Z&Wb0p*}g#u=r2{Z=HD+#uUrA9Fuh^j>{OR1eTShTFk<1aAyDr~OJb3C451+aG5Flb z*F-=_lp}@IGfdx0=mX&LB;)bD%=F}id7C{{9OfO?|1$KIX4|>XFzFozvIP^2@W{HY zyg}E??a{bUTNd(~vrlEsj{eWGI56wP#mnA+umyGA|TS$GF z+XDL(Fr<-=a@(us5E58az%!Jp1KYjm_mz_`Mok;OpPPR9s(EHza`qL6$^kH7$e~3l zMz7v5_b~t%ecTV>-Kw53mnPc}fS)981Xse}tAz`zVbm5Ms4ji_oI?$vUZC0lF5eDa z!fsr&RBty5U9N*vdj{K7-wH1S?tk?%KP9Z;F51 z1{(EX*}4vruG+01Z9yFQy{b?3LfniI4ETdKYQ5i1Bjn#sH}yxpd+Ukvc${1bCAQ&P zIlTzwHTXD>oFwof==xS0bT?WGb}u&W(vc}*upR3eb=O)y*5yF1IFX%W#8;=CetgS-2hVf}FS`_oqPGY`q88OWjhpGC_>x>vUUc64Zk zqv*D@UpXwPETOS&ZU?T64&_!Jx4@5#Cx{EZ?_jcU$~oAuHjFd01>ulLb>oC1qCDof{vat z#mXxd3vZ7FZa9nf&N<2Uldx%4kGUPthzq`*R?IZpwP%(U{opGbh1AN5{IvwtW5L!% zd`UFRsY?$bPH`qB8h9N3N_0MJH=l&v!h6qLK7Bm0bQiTcYFq8?^Yb-3c!Bea${}EQ z>y)_9=r<^sS7TlSVM;~|;w^|}KlU(s&<0=cubL#s)~*UDodETS>hatd%}~s^&2Y?U%wWt!%~;LQ z%y`Z4%;?PEwz2y>`ndWu`mp;f`l$P)Bq+?F3Ux)i8j^A_G7*m8C*UTaCg8pPHJ6$I z+)!kpM4>(sB!zhY=^19i+rcZr@jwwnp@jxWkQL&q!BoI&K`}vT0yrh$3Q0ML)ZjB= zKf$E}VxeS1r6iyzDUuK%aQlEpDE&|+33y5}Ot=y#4JgJ?L`qadsAMQf32aKh6-*$2 zof0bva0OTg5cDCr0nPv?zXA_w3OKqi4Q16TmyNg$~K_5nl^nOx8XBB3y5 z04WsC{T%@_LO1j)v~9;e-B5NYQ-B!4E6EknwrOYxv>03<^drKyWuJbZT@iubLzP z^GLTX+s6)I2Lz-0kzaB5sX~=Qi9@{-UXgC&ZtM3Y0;U1^@VT%eZ~{<-(4+{YFr;v# zP^9pv(C~n_PzESf0679FG%2hIydUlr;Z9DX7hceF&Fm`d= zg`mDsNPmpXd~p6h3+rG)G5WS)I35A0Vu0}fFT?*nMG%Gb*2v5Q=Uou$|0Vp``upo+ zB&74b&2;AG6!?%w&xES4T>dy!dR3ll) z##x&nYed&lS2t&4934Bk;1g6(l2G;^Zt5uO&UGR^FLOm{uz|Q_jEBo-8AV`R1&C$h zq7&fnc!;qtjSJ#RicvagSy)02QS`M2PIi1VZXFaks5q_q6huB98DZ6lPu38$?uhSF zsJ4E&gRYzTaaHn&!jz|wbS&y)u2!sj(>+(X!rzTXMNTI5xsOZqrsxwBP&~0CNQK7b zFA>_lGy;VRYvAMeS}Qp5^xf8>?M_zsC1*Zmp$@^k^;{Jf6$bwDl$`m3FmsalTp?uA z$Xki|s2!E00#d%u8VqC87>=?}@8)RWT+XsCRZoRq_Uqtj4-eeY-E2w6cg#i9Pd0_I zO?bAGbo#c6ZaNPIGNpfdiA!M{i)XRNBrA1#Fi~kEQIwt{{h?;^Cx0B`nvfsbdh{1E zvbW_nfz+X1Vhx`c`34KzO3H-X{C>Un8h!CnFz8>;PJOKJ^7Gl-KK{`vwbZP(L07{b zBwE?T1X@xxnbXO)xs{DzrtZBXGR)z&UBJuv4d+}XkjvXbNwrCqyTJ9TV{el{M372cD%NK0JU$VG5{LZkk~`ns%ez&mHvY5+ zEZ28cj`y>9y_)a36o1$^$`PL|Zfl=hgpFfL#;fc&={R4@UlF9s#Y@lWo`LzNeFEs% z0L7XG)Ag|W@GS)Y1M|X)#W!TbTs6aSc?&^^viDxP*IqiyFsnYua4!CZHo}H!Cf-MF z>x5`v2a2c#yDUyOOV-P>DD;~CJE1Lre<0rvt9WZ| zMAshJmE5TqP4pDul0whNOLb3B^Qra_@*w-&=GCV{UuczQJK-}cF?dsmy2o24;57Pf z5ll6Ot69ks97kcYDH@T+xlzj@hBsUn;V!`93;x4x>)N!_(}ig z^3*z9Iyq`4y;^Wr;UZ&{E7iZP)y&=sS*T*W9wHU6OOzF%s(bYs<@hHPN7WhvLbT!H_`XxPuT@f_X&j^FvxLQuKznI3ojLHSpGP8YAwI;;}pdr zG|?GaI-|pJzwl{YHCI|S`#gq?eYO!XFb;;-Qo=$wXWafHORj0~=3<+yjig`nTU5_T|f1r;}_pELN1uV?U2ME^j6X0h><0WmfIgHDQZ0mgxM6iZw zRL$T|uZg}SkMLty#BWsdWlR~@a~!rN26HsM%r^1!nfzPe zUW0$2kIni|=IFP&Nl~*I?4asxLEX#4NVHI)MT|4y9w(fexxe5;@oe=$X8Q2Z8D4oo z>p(H!Md;ZyGXst#C0$Tpn)?s*MQKVh%$1)NQ**XIFJhiMM*roNc_A(eLc7Kw<^l?+ zO~At_PDqJ?=n>^C-N*zX*aSwDH-tu>B`y7c%W&XY)ZUwK8j);d5PnY6}JuX2$8|&t>m>!Bs2N>Nm@pxy*=V=IV^5 zVSHq|@A!hyLMBIvGM))8VBc0|?)LB!@JCY6$>o`3l99nBQnZzr|3cNTs#=M;Lg?9Q zBx{2wQoM3x=0{;;+bVxInGE}Oh(B5_T|aLsaNcmfGk0qvpNK&Hdhrd(lkp?NaZy=7 zSkq!~XKM@{pCV0?w;>FPdMz?W}VZzhPT^i=S~IKxW4jrvDR~LwoSpj19?vy1m|jzO7zYJV_L=3(3Y5-_KlJPsL{#jsoz?D=ynl~TV~1er#WNC=nvZ)zRmq1VbvLN$wb z+59p2bAmaPJ)x^df=(5Eu#EC+boL__?=_9X+?<0&I_CFbqd{N_iXpE`6x(=K3gbg* z^RrN9P6dZ_dp-i5wLAUb*|53|Q&w(ThFsC3dk<5z{60FT2zoxhL5!rx6wNv7i5$7M zK@giLXvUCbB8%q2(msdvd@{122t$_G-jca!S*B7PBN3-2q?wDgCfM5W!hM5ED<=>Kry;ZZq0S{e(9 zK@w1kkrDk5z#4Q_W!k2G84nKBEGf);()95bHRVZj!zv%689B5;zurdITj|CWtE?iT#aQM)M*!sq8ENdH+x_;-&|{PA*j@F zU}*!m<$rMgH((e`q%2_cZDLK#j@|?(5sw?s%t=x%h;SoC{v6J86}vJcS`j+y6^^Mv zxVxLD#ar*pCzm22;+K;~G1xGr=OR>_#;Mghbvm;-pAm&#Fg=&?qU?U2x__*L?)?>n zdkWvfC1xbLp$+z(r}-U}Cg#S)q4%RO?r?wl2O|21k5&vO*SMeY^~7&&&GhC}gZtS= zd%^3Uv-vPP%`WWupFZ8X$KV=5D5<7@)Vr4aC@P>gTnq_bi)-2}IETb|x87^`fRJ?to1)K6~9 z>YQ0FY89rO4O<=T4L3`y`6r{N9N3y5a0wZXxY^Yw7jpy0PZ#Td|5T;79quR|1lF-H zU8s6|3;Zk7M9oNd#G0M2%j2w}V)6uPVXYCiwIMVTiyPi=&NR2l$5c|9s71w7VIH5% zS?|SPg#d!y(CS}ln~&PLfi{BlMJ+V6pqDAK0@RW+u%=whpYcg6sf<+KJOwJg}_82UG7U-cp0o5jWg3+PUzny7Bp8xNtx&yIIQ?lR% zB``H5u}<7_8Ya1I_;&}TZnkGRagK)x;6oQ;kekvW|yOk_U@chUP($)nA9O5%pnio}E@KRQ5FoQX3auOg+9Qa`Wy8Hhdw873MPpoxxKom&lCAr5|(!J^JYwiA4$ zQf!$kn6U$maPu`}AL{D08gkH=1O&~(_F#UbzGN?TX}*2EgN308QA$uY|H-~mwC#pz z$z0d?ts4odDt4rjRAv89x>*sw-C$$=rpzvOO8&?14wm7_aCH9JSd-gH`|nzol$xaB z2RQ{uDGPnp0d3)S5axsvoz!og@3!3htc0D?xdjEW_M;J^3kTqwwSA4Xz3X?^YRg1M z7$BXTiMcu0y7>>uky2k7Xsa4bL=EK%sRfhy{OJ^wOE^WWYoP5&(TwLpd#4t2Sbt=_ z@GZ#>lPXUzHLW+-7+t0AmaoxGLS8jTEkG$&hWkLtoE}mOnQ*PR)3(vRAx@()Md2M| zcoQ%1dJCj!IDDmgl~qcl#)26zkP(4pN&^;YFe0<1rK*iROB`dCgY=aX3W@?P#rTi4 z#DGr%;^LkPtC)WWQR`@TN@%IBe@zUJhRpDxe2S}CjX@FIa6I&GO1kj!GVzUR4$DA+ zc@@bNPSOsE_CVRUbZqs9(+FhvgIMIMHq-x01wZf+*)nY8d|tJ)vc)CH5%}~?F5S89 zP>DHfeJ!b2TMDu2N^8m}ck9a}=nCUOo4xwZTe+Yypi#3bl2A#wtB6ml%WrIfH~#zT z>oHvZpjpw}5m!6*M!$?=z=$=siZBa6*X0=sd}KpFu#Z{1%G@&C#uu#e9pb2Vxdsu zO~Fe$(!aL!y1u$Q(zuRbg%U)Q+u!4d^%G~%Y#+-OY6@^Q)Z(x{|5|J3=>1ib?r=g# zx}>_;>vl?_x~tmCMpjFaz5pZBh(3=w)h@wVxchp{woQerGbJ}5Zl3fSP6K+RAhV^5 zJDU`Zi8Y3H@dB!6oz5_3paRyI;8t5{fLImjIFHWCi;Zg57^xuv+k%CTf%8cmzOiDl zk=EK;erzl`z$v|?n#DrRL9tLr6Z;zRna87KVFl6HSfJW9U6~Fl#!dwf=P$g>7vj9$ z#LF;DlSBhN4EOu?Q5~$1jDb|Mmj33(i@x06Q`^#gws!mA@r%rX6B@qKfC>jWZ#X?n zy@k}ieLd&FAyhlh+lhk>7!z7#yEJUnQo5iB|pPH39ZK z)m65#A?C%+0wE0nW^ZE5r}x^u_4D@%HMkJUU1IXP#ajD#Rwu~ZzipZMdwAIcS&o)f z6ehX`t$%xa|Fr$J5*ak@^uJlZq0PLIgH|@QvH54!8@Xw{sE=w8KW@*sCDiQwD`wpB z$I{k{eTPNJ!Gf%;)jCRi;G{9#8Z@|nK(Y($CDE|wPh0oLd~=MZgFDemiTvhI)>-q+ z41}4JTi+bLavFcJ6>Q!{cbgD#>8B4`K?%K5XVnzd4vKXx z_&kAR$JX8o6&`t8cKw>CH%ycc)Jzpg&jb+P1h67rEPf$pUO%Y3)elyhub^BF^OQ68 zSqN_)Y80aBClcF@`t?X4T{U%GK3KMV3o+5VEYgBFiAuUPjNRomuk|e`r=~pfqp(_R z()4LC-%WXyTktYL2TM-poanbShct~_+OooLe6 ztPQG3P}U?~|5di>r{KAKv=rM+wnX%DD`^4Jm?MA2AyY?ABXT9k`6h2o#k8f5665Qa z-`TAbuZrXbT{nGUUY3+21u1DHH*|;7J%J7mc^D+hWqyI`zCOn3mb1CJ&n$8;uZtM3 zl`6mUm6hYhL|?xZvis{SHnW}|$M|@b@n?=!cJ%Gn%Kvc`@{nq%eUHBHZmIExT@j<*O~z_MK{J!Haz;=YVS<+C!w6vtyB0+pAz# zYUs#7lnkUewWWqBhchIr(_znJw|A+TeVlnZ;RIpZGC`AfuS`K3^5*B8*yQ8gw)i_i zlzphp;Om2GI^r>$_){4zg}`)8QRL6R+iXuqAHVTCp!3~Nww|tC2(nhHchOChE1P<$ zlzBXxwIT1qsvyzoY6!^Ca)99_(|mytA>QyN)38~FR}?Hw1L<5p#j_A>IX5JkXAsip zQLzaxUi6# zF|w;~U|3Og)(waG^3=3?`(xuIp0)bcR=~V-gjoyOe+CP3bCNYrBlI~=B|FtduiY7_ zRk@foA=LQ7(qyy1e}%xVg>a6r_MKwC*wAt{Rw_3;+|$Bl9d&1x+2W5!$qswef(f&N z`{TIasH_^cl4k{aZ;&Z==eM;sAX!g|x<^`%1@0S>8~f{Z z=4B_vn4wf}~mZJc+-g3XM z)?I9YyvM9obrK+MvLM3S%+dE8KXh7_sYRMytsrHR+MX*GC}T-d--GR6>K_O9tD^>8 z{23Py(Zb@pWr;@z3uap*d9-?4M6vBnW{h^ZdaN4zwN#~rz2 zNw~^7hg&`#OJA_<$(FPRTKQwzaDQrC6&M|~J*nmJ6sLn^{~~*r;+OLF2sK#+p&g4R zgvy$$){U{OaGdD>Ie?84ovp|Wkd}7W^={=XZmDGRUo3;)%1lH{SGsB-IJo*k$+6>~ z2JGl49?IjTqbnDhgr4$cA_*^q^PGLp{Mt(Sl=Q7Qrsj^7K^kH;Tg6GdQbFtTmbi95 zVoII?PtV0Nv_KSZU%L-q7J$tQI;SR?p8xAhnD6xA>_@Dc$Erex!Y7KZhT+$lOmMjK9dHP&rk zZXA$x+F#4SbIH%p5T#2OnbND~OVkGowRG@W_M0?TCo!-wF93hE>7@DMbzCFlg;VdSzA^jHm0#Fc8pr9`dBhP1>xFj$@RjWSq&+3;QE^+8S0!atof|fU>ME&RkgN zJ#8(yiEi1&e8p64;pjWD$Igb-ug*Pf@s4f8s;FBUda0zeQrCRvUsG4JJ9$b4`)!mt z7}+w#M-n-dcepF*Bw=!-bEHxbza&&M_L+xUX<0@! z((ZA6*0H4=wkB`ml&D7S=s%F+)NbZhL3QS$$xu&jqA&c!ahZY6) z{7FYL!SNngUKa`Wp=Nz$JY`m8;hcP@N^K&=-lpy?QanayJ zK|Mm`!}7=EqCec@$N?mCEjBsoj`bwUY{df?jfP<>NZ>Hs5DkMB)H(dG;1D@T!=>60X)WNjNvngt;*BHQr$n9inzXHx7S=882j=?OMfgB~Hz zY_@YG0#h@A5Tb#pbj$WMg<^5udG#)ibib^AC7%_adWmzZe6Xz&nopy)=XI( z44k7Cx}(y{r{(SeodZ`w!nD^y#^KRbU58Z*Oj(=qCp`t#x7VuDN^YJL2;fk9DV9(F z;cq^5QA#Y~P!dXrH|Q@Nf%8xdqfJ98iNMVpG^ug30> zPh~!zyurwTsd~2DG$AMuo0%E`m+}Y4PBd0I#7zU)N=ap4R9-;BP8Ps`P;WYMzh@<$ zKzLOKKu?loOB>apxRS0zOX?BB%d`ls=19i1j{z{6Dx!~+^1$+3z)vnTycK+Ux{zuk z6qGqOZG`z0RQ2^NT~>ZX8$=#Q%rB!y>SYNTzh2`Q@x0~^o66h0FKfS(dZm*DqF)JM zhvTPV5?$wTo|Y6jCv}d z&H6x1aQ+Q#b(~paP$O$EA609yXnagF0L4Y4TJO36qTU3~ewnkQGwgnbR>5*(N>pUn zkuUYrfM=umcqv5VCn@~{Lv886p<7I$z(HK%L_Ji)1vAR0WRH1CGgi&fN~lZXOAKc@ z;Z({X5P-=pc_v?TD9x$4 zi()bm`(Z0qMA*jfkCm2K+$b8x@(x$$S>hLD&&K+JIwCrHx?X8w3afElX9YdMMv5eF zL-%2r@Fia}tN$#>hVB7A%JfhxJ#;PWbGEEGFNhbpO|_KRM0`;OzDla}D}GqkNxfld z82;SXJ-QLxJeDEG-z7a7-+hxp(1cKo$+@3AA>?c>Q?yeS8uUJ4jN~+i{will>tT7; zD-E%P4#ZiF$+lydZ0NgEXp4`d6Jh^cT~bo=RxuYcu}PGQn-Dr<@_0MHDxaliyZAy} zthYvqUKFO<-zI0{l_zu=S+NTE?dB0(d#UW4s|*BgV+;A7 zL}IA8%VR^*YTN9rIXHEvG*-%<&2UZ8Wk!|UJb`NV1br@WYS-*)QQ;`*p?962VY%-@v#a25dQzzf%qy!bC6J5Y>H1&$ zM{N%kt7ocRpmk`}kp^!ZP_;%s4EYkX?prZ2*eMynjmEhSVla9$`PU3tYS6+a-}!Wn zLs&5)CX&)m&*^_|9=nl5xoQ#)ePU*P=QBy%lq4@9Ul71fy8g|5SD!8=`NbF2G&1J-?Yp2`tejm4s$8mNcjZ9ZsHQXz*%`z?J zE$tIFQ9w)w-+)*8j`jTqzguqZJa)$4$Tzb5?ncVtH%p3t97#2vK7IkgkwO0YL{k~K z2D74-_15KUuIb~G!8assuc9WbFIbIKe?ry2H8y%Ql4-2W3FYr%N!ltmcR<@nPI;pU z#Vx^`r%}FW*{UHU=gBf`m2p=TT2-NsRrSlYE4grSQNCf7%;e%>3Su&zJHS@($)Zg0 zD z2l$laSG8j1J&e7O(OPNARNSWPLC0IGAANCTIc-lox<#=p^~M2qGUyGJE1b_mBT6RC z&_Co~6Q4G24dV(r^6*N`5Wr1Ac6V)-2BNd5qf%}=2>DwN#uB@-I7D*Ng;Ha6FNg}~g?S$@z# zLjI{H$C9ZX8|0AM+@7N)=lToMP)%g_;x1noj<+74?`F3@w5^icGPaU}%P4TFjKW6o>$9K8vWA9+ljiIj}xVgl~Q3;&KZ*4(R0NkD6Z3tS+8=GDLw6CekM{YLJ!VOHc8jqwt8+=#7?hmx8qA zm@f0@M7V8N;*ED0NF$q=rQ><=E+mG!W0$*cWM0D)zOXxgwl`{ch`L>+=sN7Avt|m{ zFXq;}vuRVW1-|c3bt;X+Tk{RA8Z7jEy`N)x1f2wq_TuUz;i-@ zLr7Ym>FMY__TdmYOT(xb%R~R{H{}MV)3A+Z4yW4?5AOY#kwFv4*+`iz6W;S2bdEct zn!@wc*Blf}qgE-SRY5l@M|GddTysPW=-F@X)qcG)=sB^t&bPq6TEnJ-#ivN+8Vw&( zb=T&|3%Td8-){g?h^jK@SqRddW94G=&oj$IO6je&Y^1-Zos}}LDC#P(8_O$Ame8xm zbec7?ST6t8<`!{ap({4k2uM>Qn-aD{84z%3Nzj`<5})D@2Cx*N)4HAs{|tOTA|jA8 zr+QjtU;D$lU%+JeGDC-QsjrS=#^KEY38Oj(LyBb@X| zX(xSw@CkIOK_RZIb~w| z)Jc&S-5l<%Roi9gipbp?^qNbBpt8K;uu3#+6SkqDG=Z)w{mN9%-B*;<{KX3UaQ$KI zx6sg)QKSw{MwORB^+$Ft>&_oyJQbW~oAMPT_vt8w9t9oc#hM8f32Z^yw*4IYV$6EoTJom{hr}Dq_3yJPhAb%f9G6iIFB4p>&lrj?lDM~3ye+Q_l zV=75j=Rf{Dj1xna7a}e~hZJoH?M^je2()6w9j5S$IGF={6~6vNJU{?x+`HTn)Cr<+EdsG%D7usWDo_ zbU$pvPyMShshu(^Fqo1)m+-q`WocscDq}idt0f=+-ek%9*DkeTk!oEOp}1f_#SKH6 z?>@fwaB|_7Wfrz@YQ{zF)H$^ylrmUr_{5EEj$_uDsVr{3MP-vkgQ6W=xcQjN>3{QT zAMt+l!Z<-V%yf!sL;}ePDKr9tAZa9lvwq20$;e!R{XTQye;d`7V}Airm2+8sjY1~` z)F0JMEErlZ=SiFe7kiCG=DYYG3JAU>CuP}_5(^S2MhJsSUWj632}cL2!Kl>nhf zKPxaLq3^Y!Q2}T5W=hH`D99`NSgK{qeNsGTJU?KZ9Rl!41B^FU){X3`=$L9$Q`q0~ zu>R;_Lg2hafAy!G*LeEyD=WS#}$rj(9egD1hAFG z;qH9?-p)84M}A7^ttXqT%Y^*_CcG)-@DLG$(<*@OU@S2$IWqLnJ-nFs{{hGuPA<-GQZz=r*r6UT>ipxETpgQ6li?HS>9z@ znis{CVfRpET3AM&A}wb=YFexB#3 zL@G<#_wkXp_J@4k@&SEp!+qVIbUm%gO-{Ph$o{)vv{BVP3v2XUsWOE^sr`4(eyO2-FZ&%-){y34v} ze(z?;mtMz3|Ieg%8uFq=!B_OKuWBb~>J^(lP60xe8Hm{b(#!RY=ouAtF8yKPURAQp zGDDqhxTSHj?A!DtdR5o=vC%Dm)3bwGm$lDjsgvnGV>cRnEx6)N7MpkEBwyTUe}heO zJDP?n)SZ6rAUo$XfqA)qx>S6h-7+q*zLD{VrFb4p<9Q=H7?kDuiDLfyHqSkD`mwj; zQ0=sUI$Vb5b0zX@=cnzPjM1=&tt~P8wm4v%WM=bz7VSnx?8tfZt2^(K17-4x%Oaf= zlyDkzvc_ja%@!FuM-zCP`-XEUCPC_YVzIh5_S!xVECNq5inND5nv=W9)e} zSOV3OMyh>NLqE3kK1IxQsVI_KrbrTO`S z6EC6H!3%*^AC`RY&}C@e;7*TEA{W)F(zDyzxpRR#zox$^Q)oq?N zPw4uY8l!iKjB<=i zwn-+F*A4<{WIgeojPX0|-zs^AY4khn17v^gLmPNZuOoTZ_y>xmD>GF->6yN}Hi#BP z%71%ZC(E?@^p@+$y*w>QY~#)<>@WOj{)xRrznKfA_(4jNnncAbIH$j5-diwSxVsM; z#qOvu*E>-&m>G35&71hIx{5ua{GO!hjp^*mhZ-&uvOh(acxF|7`{d7788#yJ4&r5; zBgPuPK7kT0kALze;tupZz`zoLM3^st9us??p|cJfW7}{!F={4~VD?+iXObr(+_V1T zPlb40SIi<`W%mg_4UUY8{SVIGF<921ZL>Vv*4egg+qP}n_Sv>=+qP}nw(Z&PH{CrQ zJv}oK^RKev$&AdbsEDe}b+5~6gqAM^|2Lv)RC-m)hd5z2+|Vf83a>>E1b9rbHp@w& z$cnde&^{Kwx`Hrd3}G`Ws}MPvkMq*s=AJMy&c!THV;;t`7S3ZVqaAc!Qn?*pLlXPr zgTBhxe;u^3+Dg2|`45~?mfwm@o;CGsrqBk424d9(21}r(21W%&MFF#P+_hL>4u~6| zQ0oX20OCS}OKv-fEBWZO;GF08=I$xVMY!hf;=@*o58LP^H5wGp{HrNb(+*vx;0Gw$ ztMlw5YKv7h`~OD!_#e07e|(4xbSx~a|6Th?|KDYhTwJtD?smqsBDOY8|IslznA}>yc@8j>A|Fie;zncHU z`}o`Q|H=DE#|}v=ZSLr3ZeyxyZscT!$HM$O(0`^WVs2&3fJe{xyDkMDp8v6;|Fr+J z&fgVD8QYjTnbG6Xv$8WY(EdK}^qWs9Vx{k7EM#nGYh?W29>8N``9H__AKu3+F9Ba#U!b&|ALafU!Dqc)<1*dV^Y{zhW|0*T=J2{NeaBd9=;O9?`& z@=sU3cb1BLQmQ<{(me*But7^Jqn)6$qmLMH>e%crj0dtf;mS5bvZ#+3tcDPSI zXB=kUvVI({g@Hl;G}eNEGs$LL)BZVAZGg5_eWE(kK_Lgb8Q93;u25wk>DkJRcw70S zcJgTqm0bC8`^uc!^Cy>FyVh;%Q_Rzq@!yx3udeG&#t3hJGxJTpod7SS(^k3RpLYYQ zk|$dACYF~gPu?L1(xLqd&vwGE2_7&xaLM)+nuMPY7i_+9I>;=^j+95?6V;HGNMqF+ zEo5q5!HbltQ%#rql$WlMD_s!03S(A&tbbOZXuYHtz{r10hrAv|aUu?f9`@l*x#PjW zTjo11Sz`6CC)6z8MCf82?zlck&;|$gOY|b861V#?_v&?D)750qK}4aH?U0@UtT{20 z`zDd}MtLBWm8cVM+O89R%%ovHUoTJ|VEKMhrEA^3Rye0-ETcU=K2n1yLoE z1;5NHXsl9VQ1SLfie!5`e#=fLbJBRdhaOxdWPSc#`;*UtA=k$k;|^4@C3NH>G~>gi z_|S^IsIJ+l;T^GP)6WB%^?PDZhu%ALPb>WEVmp>;1+^Ktmr?Vp?1m+*MYHkawEHgE z!&!yg3E(`8k?431vjT6l`eif!y6Q741?j@@l4qZ6{6}QCMo+oOQ&81pE@3F>y>+;* z=e$JJU7z1+WneCDKNr}4=jZ>)<$K+VrR$Q+%1FpPb>PCTs2HDs^(>UJ6t5S}iVowE zrBV>BNRI4)E~*CVfR>?GVN-(+|F@z8IEwU?o(*Jb@j==LKngZxtu?BG!I0c(1&RCLE2G13 za~We$7{Txx^bA%L;KbVwy4 zVd;=|p~ixd#r|;&mBqzQp&&&lXN+@a%W}}*pVu^#ZvLZ~%Y(Y*=qRE#SehWK)X5Ps zhXe`mhfDqh3=k&*em5w3EskWSMz_QIK$92u<{sQ#TUl3tXTzX^eDjv?8-azx$LeJL zqWJCaSxy}R^HDb04aGa`p~maYP&e6lTaOcmU0>eXO46w`vhWv5OIMuQgs^>q=23c& z5E@p+UC-8F=#_QUPV@V_yD}wqXeFG*%fdIMz$}^XdQo6G!2wIqN^{hAF*X^6QBPg- z$G06FS^dfGKnPnG-Sovj)%*duZxv9kU@u^v64(Vw&n_^t>!bV6HFXl3nr| z80QrYCU|1}ocYfK(3jj5UBx?!j%R+Yc9XG>lppO{0{Jm6SXh;LikH_zYof)G$SKFN z*8O{ic05afJ0!%jBv$}DaW}BR`T1r6>W!FHXOO`H)uY{piu`fiipdxDu=5DWXZ~xZ zc3FMxarW#{RaeaXA&nk>RW`J|rjD5dUWN~)sdf4p{6FlXfd#{7*~7`9D32pH+SUj_ zCZeu586q2!1w6KnT)1Pd%_|-j9iU*A+|%oQ)qU6c_7hw&3%lr8^JbtaOHS;>52kWH z7A=CMUGzj~?eA#{<{_tcGUc94RZ#+7l3-iq8m7LkgZ4@uT0^iY_KngHI~CFESQfnN zf129(2R_(XVLV7f8j{=7^&jD3`{bmgQAn8zu&wh&=XKA5n;EddT;(e8^B&WK77C2= zOhl4G-g}cvk-+TRO1ZCaj`eX+0;#F5;_4BP*>M23Zw9OO@3oR8a-3M zUZ$4WzAzs>D{bH~xJgXIboX@~y1M$sFstt#4EWWtw%%XQUH0_~*q8auXnxg_atT5|JkyXY5n!wYWLS^-V*c~t6?o1e)fhoVb`=S-ItinMfi#|$1f_=aBO^xL#8KFl7gyio{9WK| zJZgGbTWrCf;9P>p*7U;2@GP230D+ek=?7~aqTo-?D*i5JQ&7|t-j9cB$s9q-BA4@G zge0WD>!pBA;bPlyvZcZ+>zC75wL7XI%?0qpWUmm9E^s28>M3`}A~v-GY)BWM3fvj# zOUkllfhj8rc)NScipfR8hDx7XqOqE!)H-3e#hZB*((v&xJJ8 z76P$lx#5&QBtqUtj;7W_zvKCu%^s4+_J?t4hf3~A>oVX^`*VI z)s~k`gjqSxGGZsiP2~FSVcPh=i4}Eu)VpNDy!gr-drl&9|YG7`b%^-+Qd zfN{tiB`H)9;b19Q^t1~G(iXWe3FEW$y_gK;*+Kj}zZ{w!YA8oh0}0#rldPdWbgjqh zCY&pl74GFG*q-2qS<`~DN<7l@Aj}89!%H^hXX!wlBQ3V0&6|WS0T$yJwl6yG*bQ<>Iw*+b#G~pzEvxd! zeIBa^g6*d+*D~%&XypNBm#4#Ps(@_J^ap1o4RH?-G%TPd=oJ*ifxsRa=;%^H4%RSN z%Lh}gdPHE~i;C<=Ud*u=t2$+QVfZaKtkN${i>EQ}BR44v{X1|1`Na--cJN(~7m1)egP8(YQY@vG^FDVpZexhH z@Wcyh6z2~ZNY)JUXacc8#_8`|=RZdPR~Xu}d*GO*+sIRvC+$;5oDtErds;KDfKfkS z$1n1^gzzoZs!2>fafGU*(y}3FZlKz&c7Ei00P);V)R?QXYP^eke5{eHoxb4c5=PLOZ8Vm zRUlsjUqDtv9zX10&!d$fUU}F&Uw69CFfZQY89f|h2MW!IGkPJY@fJOI?Bg3KUxJFD zKQD^6wQJBJqkq78!`+Y{EQAP;aYeO^8um~Iap`meS`i+420e@qCCy%ul6OQa`7(zc zFbvp_eIs81A07~148IWuO;dIMv7wMN)|Omzpm8yHXDKEOg&)tFX!~VqPl%2<;R~#JAHOiekIm-fD;9cqm z=Dp|vbyNe>^T;&Hm0poO;>$K^7Cq!pNl|JmZ1hBSP}QRrz9*PYd=wD-73oHhj|oL3 zUWdJ}J=dCGtRW*voojYb5z-^tP z9`buV`JpM>OvNm$ZlF^=@Q1>WH`WJoxbI>0aCd_~iaR>Vf*a9*hdSeUHvEP$P^vG& zh!!GxPPFt$BtHfz@86Na?ndj$8wFiUWZn2rlqT8p5{5>s;N2 z0ocVc#7TY;zq6ULYzEIgVw0LyvGobXR$M3EiMSIZd%`VQ;kZ|#lRrsT2;*c_v4j^0 zxGB$$Du(VX&qdNWFXZz^yQVi%1!K3I>96&-dbOk4WxgrLS z@nn%_Miu95?x+NFM2{S_op>hlq9a1i=Fx+*-OaFhbmwc3HXX|id;FknI^3w2z~1=p zKo<4UvrVP{M&oCr?8G}=-jzmY0yGusK1%(24|)LGoB>hlY1P%s5Vni>)WM24zy7F| zxgK1Myu$s<8~Z`GLy}!QLnM0F`DgWqn~QSx6(wq_pe}iM^%U#Sa;W97qR!jl(0x-@ z?)&d#?C}F#rKm3y(y64aDApjG7sec)HwOC<+Un2W8k23Kcrk{ALa~2{NcX6EU?APR zom9S{)d$J_^w-E@Cum{=PFT;lqT3))$y*87x3PV*aV?7YBS#u2ag4A!5$i3uoD0dBA>LI3sa+4Q)<;ipCaq9_ROjj zKEdW()*-oHFZk0ER}%6+owvmM1p7FHbo=UqH=!x=1YW7WPz!8QKN!|87@8w&s~nMp zI$ol8{*i7&2cZaq5uvPdCVaqjKc-UBslf$T+rvIM%`#ZM^|)~{^{T&o(&?&&5V`?P zzklh!l>v;mi&vR~fDts^MWVb*?aTGDyyS4>=+! zKi>EjJOJlij>aisBY?&HY8HJi4oXZ?pYf-N9CDUk+`|w3RLfvRBaF=;NA@5$=(#Ah zfYqQ@m^(*c?USuU&i8I1=ZFkAo%e5PAFvNTP)t4mDzskNpY8Z9{P13YftJp@;-U1% zd)vEapMaq{AHn^Ip1#j>W;e}xXxoUI;f?$vl#%?R4AoUtZ9^F`4Z43VZ%}v3E4D6= zPqw-?vRdYC%^Y)0u=G^fzOT_psu0DUM;|h>VGqbr)rU)@XeGJJ$+xm6hlWd|18^fF zlG2+e*ki=H*M{DGGp<(~Pjh|VV7&1#zJsM6R@}Td_|rI5*({!J4i@c;To<{VU4^GI z$IV}rGcI_P9fKbK=r3yyC4G8w*k4SSM}F3$;GTMdV5?WdCNe==U2SJQh1(O<`Ii- zRJpCUSh~N6(I!xapD6_dT@jbCy@+&MT>cd0p#p=5FQyXru@~dfhVi6Pl>?5bj6a{J zA$|RiQ>o>`7cM;^GJ5WTq$@ytc^%2c+P|+{IHfFz6b<_oy&VPnQs2o7G(|C4``GXDJG1%wy7cfV^Ai4YHf|Akj~i-+)+|4?*=M~n9d0tRRSpp z0)~p>(>S(2(8IokTnx;y}z*FI4QnH#Itd6`}c+i?4}kMhC@stoF%C6a^YTM zYc6*gxLE>s)jGJ?k%thNhVqb}rH5IM;%*~j`iS#2@#l>XzZfq_n(l%vrlQmzX-GCz zj*W+~fo%IPS?Mm_g+1l!2OO7+t>sX;CoE4h{bt$pXsssI$N`f($a&%6ayMazs?;+N zb39_~)Ts8ygEr^Sd&P!k!~IcoXF5**@wC`oNx~;BGEvD#wjp7Jj#t?1P0(nB74^LW zP>ra1+GN_Hh+!xBwshw7SP=8J)F`BhF*2BV-q?VCiB!Beujp|FbGw9&ijKUz50jak z5`4y1+{Dq*$q_D0dcwo00uVsX9Po0yB)ekR)J+R-%tez(8sjBaU(VcMqFx``En)1i z{mxy1fK=k(BteP*jVj$8`Cz%-+)p9_Az{K{Jq}#l1mYwL1(sm9WF8^pF|(?R^hpCF zL)V$bap3yK3hwr;W(XzWOckuHf^01M(~9~Q`u6^r#!;()v)kILxBhcEqZX_v;D?XG zz#2$YSy&knuP%=}zndr;Ns=k?`2B-1kM(>Yba6h>3evW`$^lx+^pS3z<(ou55NY-tHWWsv&V>D7u?niqvAd6iNWhXoMax>}6H&q9{Hz{6%!gaVkTNg3D??f* zZORO`D^sfEV!G14L&v6Q0A$Lbeq=wrhPZm;LM4R6uvKcKE*b4zhJ-|<-)OOW&xC0Z zTEvirblhIBk&(&q-%UJhjgX^xSYeh@yrA5v+VDw#$Ywh)nh+HMF_mqh1ZDk34h2TV z{eEA2lH*cEZ(?;y3uVZ(wTv3r7vY!Dcut)uE}mLLnwv~EU(*9k$!8a3w9D;!^S=JD zUliZGD^J-Rnb;;mB^g)a$3fmOndMW-#HKg%oL+0aaC`m}IzC5@uBwEMX;s(s$otB3 z!)uBCT8P>8&fdbfWOn?o{fbsCZ@cM%6fYA73}}YVhoDZ0B89aJ0qePyL|6Q&b7b;q z;)ffzeI2wX)2Nt@;63Vdam3727NaHw+VmkkLI(dl(E`03oYBun2t*q}qQ|BgMz$O3 zU1SOsfdt!!RI6ZCT3n`qkFle$prF1gp=tIya!Mle_wtS?_*4q9Q3%JFr1^si1NGj( z)|THZ6gqvjoMpz~!=dt;^{MxRKG8T|usdc>60%-`lg8|Bo4BAF3}OifN+eJg%SfuA z1MIB`5Ojp?y+~3s?4}E={msc0%5Xo)t^@_;6++Y9ngRP*-Z}-b292U(;n1fx3=V~Y z5rh1T91`9#1R@{^iW2|6y{Oh`X@^LaR}CT@k%M8bgkzo3tP5^Vozd1{kmifjMs-ZW z5>rf1c^Lz({eEHR8s+)l2U7G_<}kqg_(234-W(&k z`|C%J0!7=__1d-Ck>0aA5)3ge`qU|neD2;1YIt?(RcP7*k6r$Ux6}8sIG&i!{6vZj z-d$eP!PJn>W1kXPaQad=8}@T;NKCR+IisWr?(4|@JCZQt3V-ha>D!O@>+Bj?+80+V zTe2KSkF)NLbhs`%>4)@9uje*${+F%2ottr+)L4xLx$T{&UN}_xTcZ^52NVl^N{c<` zLw7L&+INY>hH#=k5%!)M8qr4{I>s_2V=Z?cj^%06Bqq>99FcqaUf>&Mqg`ReP7yTV2X&@A3QVSx`RP z3?rD}RW+KAYl;!aPq@4~Djjw<50AfR)|4%!o60&1uDnbAB#oO1W^3%Vq{nMUI;{Gs zT3vz#OKZ*?0a>T`Cu(wV5Evm0%HoM&uSx+^9#m#PoPyRqNzl?3D_L{G@Zs=cF{iteCh*x+jltbW%=*o6jP~_PrL4ODA)@W0im8+FLGtlv7*6Nq>F~_m=8{

RhKgcc!elJ!th9U}b_GGux#|mm_L3D3{_$j`OM` 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 WI-E?s2Zlpc_)_%#`

+ } + TKPreviewChangedEvent = procedure(Sender: TObject) of object; + + { @abstract(Declares the information structure for the @link(TKCustomControl.MeasurePages) method) +
    + Members: +
  • OutlineWidth - printed outline width (maximum of all pages) in desktop pixels
  • +
  • OutlineHeight - printed outline height (maximum of all pages) in desktop pixels
  • +
  • HorzPageCount - number of pages to split a wide shape into
  • +
  • VertPageCount - number of pages to split a tall shape into
  • +
  • PageCount - total number of pages for 1 copy. Might be HorzPageCount * VertPageCount + but does not necessarilly have to be.
  • +
+ } + TKPrintMeasureInfo = record + OutlineWidth: Integer; + OutlineHeight: Integer; + HorzPageCount: Integer; + VertPageCount: Integer; + PageCount: Integer; + end; + + { Declares possible values for the Status parameter in the @link(TKPrintNotifyEvent) event } + TKPrintStatus = ( + { This event occurs at the beginning of the print job - you may show an Abort dialog here } + epsBegin, + { This event occurs after each page has been printed - you may update the Page/Copy information + in the Abort dialog } + epsNewPage, + { This event occurs at the end of the print job - you may hide the Abort dialog here } + epsEnd + ); + + { @abstract(Declares @link(TKCustomControl.OnPrintNotify) event handler) +
    + Parameters: +
  • Sender - identifies the event caller
  • +
  • Status - specifies the event type
  • +
  • Abort - set to True to abort the print job
  • +
+ Remark: At certain time slots, the print spooler allows the message queue + to be processed for the thread where the print job is running. This e.g. allows + the user to press a button on the Abort dialog. Because this message loop can be invoked + e.g. during a Printer.Canvas.TextRect function and any painting messages may hover in + the message queue, any functions used both to print a job and to process particular + messages should be reentrant to avoid conflicts. Perhaps should print jobs be run + in seperate threads? + } + TKPrintNotifyEvent = procedure(Sender: TObject; Status: TKPrintStatus; + var Abort: Boolean) of object; + + { @abstract(Declares @link(TKCustomControl.OnPrintPaint) event handler) +
    + Parameters: +
  • Sender - identifies the event caller
  • +
+ } + TKPrintPaintEvent = procedure(Sender: TObject) of object; + + TKPrintPageSetup = class; + TKPrintPreview = class; + + { Base class for all visible controls in KControls. } + TKCustomControl = class(TCustomControl) + private + {$IFNDEF FPC} + FBorderStyle: TBorderStyle; + {$ENDIF} + {$IFNDEF COMPILER10_UP} + FMouseInClient: Boolean; + {$ENDIF} + FMemoryCanvas: TCanvas; + FMemoryCanvasRect: TRect; + FPageSetup: TKPrintPageSetup; + FUpdateLock: Integer; + FOnPrintNotify: TKPrintNotifyEvent; + FOnPrintPaint: TKPrintPaintEvent; + {$IFNDEF FPC} + procedure CMCancelMode(var Msg: TMessage); message CM_CANCELMODE; + procedure CMCtl3DChanged(var Msg: TMessage); message CM_CTL3DCHANGED; + {$ENDIF} + procedure CMMouseLeave(var Msg: TLMessage); message CM_MOUSELEAVE; + function GetCanPrint: Boolean; + function GetPageSetup: TKPrintPageSetup; + function GetPageSetupAllocated: Boolean; + procedure KMLateUpdate(var Msg: TLMessage); message KM_LATEUPDATE; + {$IFNDEF FPC} + procedure SetBorderStyle(Value: TBorderStyle); + {$ENDIF} + procedure SetPageSetup(Value: TKPrintPageSetup); + {$IFNDEF FPC} + procedure WMCancelMode(var Msg: TWMCancelMode); message WM_CANCELMODE; + {$ENDIF} + {$IFNDEF COMPILER10_UP} + procedure WMMouseLeave(var Msg: TLMessage); message KM_MOUSELEAVE; + {$ENDIF} + {$IFNDEF FPC} + procedure WMNCPaint(var Msg: TWMNCPaint); message WM_NCPAINT; + procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR; + {$ENDIF} + procedure WMSize(var Msg: TLMSize); message LM_SIZE; + {$IFNDEF FPC} + {$IFDEF USE_THEMES} + procedure WMThemeChanged(var Msg: TMessage); message WM_THEMECHANGED; + {$ENDIF} + {$ENDIF} + protected + { Holds the mutually inexclusive state as cXF... flags. } + FFlags: Cardinal; + { Defines the message queue for late update. } + FMessages: array of TLMessage; + { Gains access to the list of associated previews. } + FPreviewList: TList; + { Adds a preview control to the internal list of associated previews. } + procedure AddPreview(APreview: TKPrintPreview); + { Gives the descendant the possibility to adjust the associated TKPrintPageSetup + instance just before printing. } + procedure AdjustPageSetup; virtual; + { Cancels any dragging or resizing operations performed by mouse. } + procedure CancelMode; virtual; + { Defines additional styles. } + procedure CreateParams(var Params: TCreateParams); override; + {$IFDEF FPC} + { Overriden method. Calls @link(TKCustomControl.UpdateSize). } + procedure CreateWnd; override; + { Overriden method. Calls @link(TKCustomControl.UpdateSize). } + procedure DoOnChangeBounds; override; + {$ENDIF} + { If Value is True, includes the flag specified by AFLag to @link(FFlags). + If Value is False, excludes the flag specified by AFLag from @link(FFlags). } + procedure FlagAssign(AFlag: Cardinal; Value: Boolean); + { Excludes the flag specified by AFLag from @link(FFlags). } + procedure FlagClear(AFlag: Cardinal); + { Includes the flag specified by AFLag to @link(FFlags). } + procedure FlagSet(AFlag: Cardinal); + { If the flag specified by AFLag is included in @link(FFlags), FlagToggle + excludes it and vice versa. } + procedure FlagToggle(AFlag: Cardinal); + { Invalidates the page setup settings. If page setup is required again, + it's UpdateSettings method is called. } + procedure InvalidatePageSetup; + { Invalidates a rectangular part of the client area if control updating is not locked + by @link(TKCustomControl.LockUpdate). } + procedure InvalidateRectArea(const R: TRect); virtual; + { Returns True if the control has a selection. } + function InternalGetSelAvail: Boolean; virtual; + { Called in UnlockUpdate. Allows the changes to be reflected. } + procedure InternalUnlockUpdate; virtual; + { Determines if control can be painted with OS themes. } + function IsThemed: Boolean; virtual; + { Called from KM_LATEUPDATE. Performs late update. Override to adapt. } + procedure LateUpdate(var Msg: TLMessage); virtual; + { Updates information about printed shape. } + procedure MeasurePages(var Info: TKPrintMeasureInfo); virtual; + { Retrieves a message from message queue if there is one. Used for late update.} + function MessagePeek(out Msg: TLMessage): Boolean; + { Puts a new message into the message queue. Used for late update.} + procedure MessagePoke(const Msg: TLMessage); + { Searches the message queue for given message code. } + function MessageSearch(MsgCode: Cardinal): Boolean; + { Responds to WM_MOUSELEAVE message. } + procedure MouseFormLeave; virtual; + { Overriden method - see Delphi help. } + procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; + { Notifies all associated previews about a change in the associated page setup. } + procedure NotifyPreviews; + { Overriden method - see Delphi help. Paints the entire control client area. } + procedure Paint; override; + { Paints a page to a printer/preview canvas. } + procedure PaintPage; virtual; + { Paints the control to the specified canvas. Must always be overriden. } + procedure PaintToCanvas(ACanvas: TCanvas); virtual; abstract; + { Adds a message to message queue for late update. Set IfNotExists to True to + add that message only if the specified message code does not exist in the + message queue at this moment. } + procedure PostLateUpdate(const Msg: TLMessage; IfNotExists: Boolean = False); + { Calls the @link(TKCustomControl.OnPrintNotify) event } + procedure PrintNotify(Status: TKPrintStatus; var Abort: Boolean); virtual; + { Calls the @link(TKCustomControl.OnPrintPaint) event } + procedure PrintPaint; virtual; + { Removse a preview control to the internal list of associated previews. } + procedure RemovePreview(APreview: TKPrintPreview); + { Updates mouse cursor according to the state determined from current mouse + position. Returns True if cursor has been changed. } + function SetMouseCursor(X, Y: Integer): Boolean; virtual; + { Updates the control size. Responds to WM_SIZE under Delphi and similar + notifications under Lazarus. } + procedure UpdateSize; virtual; + public + { Creates the instance. Assigns default values to properties, allocates + default column, row and cell data. } + constructor Create(AOwner: TComponent); override; + { Destroys the instance along with all allocated column, row and cell data. + See TObject.Destroy in Delphi help. } + destructor Destroy; override; + { Determines whether a flag specified by AFlag is included in @link(FFlags). } + function Flag(AFlag: Cardinal): Boolean; + { Invalidates the entire control if control updating is not locked + by @link(TKCustomControl.LockUpdate). } + procedure Invalidate; override; + { Locks control updating so that all possibly slow operations such as all Invalidate... + methods will not be performed. This is useful e.g. when assigning many + properties at one time. Every LockUpdate call must have + a corresponding @link(TKCustomControl.UnlockUpdate) call, please use a + try-finally section. } + procedure LockUpdate; + { Prints the control. } + procedure PrintOut; + { Unlocks back to normal control updating and calls InternalUnlockUpdate + to reflect (possible) multiple changes made. Each @link(LockUpdate) call must + be always followed by the UnlockUpdate call. } + procedure UnlockUpdate; + { Returns True if control updating is not locked, i.e. there is no open + LockUpdate and UnlockUpdate pair. } + function UpdateUnlocked: Boolean; + { Determines whether a single line border is drawn around the control. + Set BorderStyle to bsSingle to add a single line border around the control. + Set BorderStyle to bsNone to omit the border. } + {$IFDEF FPC} + property BorderStyle default cBorderStyleDef; + {$ELSE} + property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default cBorderStyleDef; + {$ENDIF} + { Returns True if the control has anything to print and a printer is installed. } + property CanPrint: Boolean read GetCanPrint; + {$IFNDEF COMPILER10_UP} + { This property has the same meaning as the MouseInClient property introduced + into TWinControl in BDS 2006. } + property MouseInClient: Boolean read FMouseInClient; + {$ENDIF} + { Setting this property causes the control to be painted to MemoryCanvas in it's + Paint method. This approach replaces PaintTo as it does not work good for all + LCL widget sets. The control is painted normally on it's Canvas and then + copied only once to MemoryCanvas. MemoryCanvas is then set to nil (not freed) + to indicate the copying is complete. } + property MemoryCanvas: TCanvas read FMemoryCanvas write FMemoryCanvas; + { Specifies what rectangular part of the control should be copied on MemoryCanvas. } + property MemoryCanvasRect: TRect read FMemoryCanvasRect write FMemoryCanvasRect; + { This event is called at certain phases of the actually running print job. } + property OnPrintNotify: TKPrintNotifyEvent read FOnPrintNotify write FOnPrintNotify; + { This event is called after the shape was drawn onto the printer canvas. } + property OnPrintPaint: TKPrintPaintEvent read FOnPrintPaint write FOnPrintPaint; + { Specifies the page setup component used for this control. } + property PageSetup: TKPrintPageSetup read GetPageSetup write SetPageSetup; + {Returns True if page setup component is allocated for this control. } + property PageSetupAllocated: Boolean read GetPageSetupAllocated; + end; + + { @abstract(Class to specify the print job parameters) } + TKPrintPageSetup = class(TPersistent) + private + FActive: Boolean; + FCanvas: TCanvas; + FControl: TKCustomControl; + FCopies: Integer; + FCurrentCopy: Integer; + FCurrentPage: Integer; + FCurrentScale: Double; + FDesktopPixelsPerInchX: Integer; + FDesktopPixelsPerInchY: Integer; + FEndPage: Integer; + FFooterSpace: Double; + FHeaderSpace: Double; + FHorzPageCount: Integer; + FIsValid: Boolean; + FMarginBottom: Double; + FMarginLeft: Double; + FMarginRight: Double; + FMarginTop: Double; + FOptions: TKPrintOptions; + FOutlineHeight: Integer; + FOutlineWidth: Integer; + FPageCount: Integer; + FPageHeight: Integer; + FPageWidth: Integer; + FPaintAreaHeight: Integer; + FPaintAreaWidth: Integer; + FPreviewing: Boolean; + FPrinterFooterSpace: Integer; + FPrinterHeaderSpace: Integer; + FPrinterMarginBottom: Integer; + FPrinterMarginLeft: Integer; + FPrinterMarginLeftMirrored: Integer; + FPrinterMarginRight: Integer; + FPrinterMarginRightMirrored: Integer; + FPrinterMarginTop: Integer; + FPrinterName: string; + FPrinterPixelsPerInchX: Integer; + FPrinterPixelsPerInchY: Integer; + FPrintingMapped: Boolean; + FRange: TKPrintRange; + FStartPage: Integer; + FScale: Integer; + FTitle: string; + FUnits: TKPrintUnits; + FUpdateLock: Integer; + FValidating: Boolean; + FVertPageCount: Integer; + function GetCanPrint: Boolean; + procedure SetCopies(Value: Integer); + procedure SetEndPage(Value: Integer); + procedure SetFooterSpace(Value: Double); + procedure SetHeaderSpace(Value: Double); + procedure SetMarginBottom(Value: Double); + procedure SetMarginLeft(Value: Double); + procedure SetMarginRight(Value: Double); + procedure SetMarginTop(Value: Double); + procedure SetOptions(Value: TKPrintOptions); + procedure SetPrinterName(const Value: string); + procedure SetPrintingMapped(Value: Boolean); + procedure SetRange(Value: TKPrintRange); + procedure SetScale(Value: Integer); + procedure SetStartPage(Value: Integer); + procedure SetUnits(Value: TKPrintUnits); + function GetSelAvail: Boolean; + protected + { Called before new Units are set. Converts the margins to inches by default. } + procedure AfterUnitsChange; virtual; + { Called after new Units are set. Converts the margins from inches by default. } + procedure BeforeUnitsChange; virtual; + { Paints a page to APreview.Canvas. } + procedure PaintPageToPreview(APreview: TKPrintPreview); virtual; + { Prints the page number at the bottom of the page, horizontally centered. } + procedure PrintPageNumber(Value: Integer); virtual; + { Prints the title at the top of the page. } + procedure PrintTitle; virtual; + { Updates entire printing information. } + procedure UpdateSettings; virtual; + public + { Creates the instance. Assigns default values to properties. } + constructor Create(AControl: TKCustomControl); + { Copies shareable properties of another TKPrintPageSetup instance + to this instance. } + procedure Assign(Source: TPersistent); override; + { Returns a value mapped from desktop horizontal units to printer horizontal units. } + function HMap(Value: Integer): Integer; + { Invalidates the settings. } + procedure Invalidate; + { Prints the associated control. } + procedure PrintOut; + { Locks page setup updating. Use this if you assign many properties at the + same time. Every LockUpdate call must have a corresponding + @link(TKPrintPageSetup.UnlockUpdate) call, please use a try-finally section. } + procedure LockUpdate; virtual; + { Unlocks page setup updating and updates the page settings. + Each @link(TKPrintPageSetup.LockUpdate) call must be always followed + by the UnlockUpdate call. } + procedure UnlockUpdate; virtual; + { Returns True if updating is not locked, i.e. there is no open + LockUpdate and UnlockUpdate pair. } + function UpdateUnlocked: Boolean; virtual; + { Validates the settings. } + procedure Validate; + { Returns a value mapped from desktop vertical units to printer vertical units. } + function VMap(Value: Integer): Integer; + { Returns True if printing or previewing is active. } + property Active: Boolean read FActive; + { Returns True if the control is associated and has anything to print. } + property CanPrint: Boolean read GetCanPrint; + { Returns the Printer.Canvas or TkPrintPreview.Canvas. Do not access outside + print job. } + property Canvas: TCanvas read FCanvas; + { Returns the control to which this TKPrintPageSetup instance is assigned. } + property Control: TKCustomControl read FControl; + { Specifies the number of copies to print. } + property Copies: Integer read FCopies write SetCopies; + { Returns the currently printed copy. } + property CurrentCopy: Integer read FCurrentCopy; + { Returns the currently printed page. } + property CurrentPage: Integer read FCurrentPage; + { Returns the horizontal scale for the printed shape, without dimension. } + property CurrentScale: Double read FCurrentScale; + { Returns the amount of pixels per inch for the desktop device context's horizontal axis } + property DesktopPixelsPerInchX: Integer read FDesktopPixelsPerInchX; + { Returns the amount of pixels per inch for the desktop device context's vertical axis } + property DesktopPixelsPerInchY: Integer read FDesktopPixelsPerInchY; + { Specifies last page printed if Range is eprRange. } + property EndPage: Integer read FEndPage write SetEndPage; + { Specifies the vertical space that should stay free for application + specific footer. Value is given in Units. } + property FooterSpace: Double read FFooterSpace write SetFooterSpace; + { Specifies the vertical space that should stay free for application + specific header. Value is given in Units. } + property HeaderSpace: Double read FHeaderSpace write SetHeaderSpace; + { Returns the maximum amount of pages for horizontal axis of the control. } + property HorzPageCount: Integer read FHorzPageCount; + { Specifies the bottom margin. Value is given in Units. } + property MarginBottom: Double read FMarginBottom write SetMarginBottom; + { Specifies the left margin. Value is given in Units. } + property MarginLeft: Double read FMarginLeft write SetMarginLeft; + { Specifies the right margin. Value is given in Units. } + property MarginRight: Double read FMarginRight write SetMarginRight; + { Specifies the top margin. Value is given in Units. } + property MarginTop: Double read FMarginTop write SetMarginTop; + { Specifies the printing options. } + property Options: TKPrintOptions read FOptions write SetOptions; + { Returns the printed shape height (maximum of all pages) + in units depending on PrintingMapped.. } + property OutlineHeight: Integer read FOutlineHeight; + { Returns the printed shape width (maximum of all pages) + in units depending on PrintingMapped.. } + property OutlineWidth: Integer read FOutlineWidth; + { Returns the amount of all pages. } + property PageCount: Integer read FPageCount; + { Returns the page height in printer device context's pixels. } + property PageHeight: Integer read FPageHeight; + { Returns the page width in printer device context's pixels. } + property PageWidth: Integer read FPageWidth; + { Returns the top paint area width on canvas in units depending on PrintingMapped. } + property PaintAreaHeight: Integer read FPaintAreaHeight; + { Returns the top paint area width on canvas in units depending on PrintingMapped. } + property PaintAreaWidth: Integer read FPaintAreaWidth; + { Returns True if painting to a TKPrintPreview.Canvas is active. } + property Previewing: Boolean read FPreviewing; + { Returns the footer space in printer device context's units. } + property PrinterFooterSpace: Integer read FPrinterFooterSpace; + { Returns the header space in printer device context's units. } + property PrinterHeaderSpace: Integer read FPrinterHeaderSpace; + { Returns the bottom margin in printer device context's units. } + property PrinterMarginBottom: Integer read FPrinterMarginBottom; + { Returns the left margin in printer device context's units. } + property PrinterMarginLeft: Integer read FPrinterMarginLeft; + { Returns the left margin in printer device context's units with respect to current page. } + property PrinterMarginLeftMirrored: Integer read FPrinterMarginLeftMirrored; + { Returns the right margin in printer device context's units. } + property PrinterMarginRight: Integer read FPrinterMarginRight; + { Returns the left margin in printer device context's units with respect to current page. } + property PrinterMarginRightMirrored: Integer read FPrinterMarginRightMirrored; + { Returns the top margin in printer device context's units. } + property PrinterMarginTop: Integer read FPrinterMarginTop; + { Specifies the printer name. } + property PrinterName: string read FPrinterName write SetPrinterName; + { Returns the amount of pixels per inch for the printer device context's horizontal axis } + property PrinterPixelsPerInchX: Integer read FPrinterPixelsPerInchX; + { Returns the amount of pixels per inch for the printer device context's vertical axis } + property PrinterPixelsPerInchY: Integer read FPrinterPixelsPerInchY; + { Specifies the units for printing the control's shape and OutlineX properties. + If True, those extents are given in printer device context's pixels, + otherwise in desktop device context's pixels. It can be adjusted by the descendant + in the AdjustPageSetup method. } + property PrintingMapped: Boolean read FPrintingMapped write SetPrintingMapped; + { Specifies the printing range. } + property Range: TKPrintRange read FRange write SetRange; + { Returns True if the associated control has a selection. } + property SelAvail: Boolean read GetSelAvail; + { Specifies first page printed if Range is eprRange. } + property StartPage: Integer read FStartPage write SetStartPage; + { Specifies the requested scale for the printed shape, in percent. + If epoFitToPage is specified in Options, this parameter is ignored. } + property Scale: Integer read FScale write SetScale; + { Specifies the document title as it appears in printer manager. } + property Title: string read FTitle write FTitle; + { Specifies the units for print margins. } + property Units: TKPrintUnits read FUnits write SetUnits; + { Returns the maximum amount of pages for vertical axis of the control. } + property VertPageCount: Integer read FVertPageCount; + end; + + { @abstract(Container for all colors used by @link(TKPrintPreview) class) + This container allows to group many colors into one item in object inspector. + Colors are accessible via published properties or several public Color* + properties. } + TKPreviewColors = class(TPersistent) + private + FPreview: TKPrintPreview; + function GetColor(Index: TKPreviewColorIndex): TColor; + function GetColorEx(Index: TKPreviewColorIndex): TColor; + procedure SetColor(Index: TKPreviewColorIndex; Value: TColor); + procedure SetColorEx(Index: TKPreviewColorIndex; Value: TColor); + procedure SetColors(const Value: TKColorArray); + protected + FColors: TKColorArray; + { Initializes the color array. } + procedure Initialize; virtual; + { Returns the specific color according to ColorScheme. } + function InternalGetColor(Index: TKPreviewColorIndex): TColor; virtual; + { Replaces the specific color. } + procedure InternalSetColor(Index: TKPreviewColorIndex; Value: TColor); virtual; + public + { Creates the instance. You can create a custom instance and pass it + e.g. to a @link(TKPrintPreview.Colors) property. The APreview parameter has no meaning + in this case and you may set it to nil. } + constructor Create(APreview: TKPrintPreview); + { Copies the properties of another instance that inherits from + TPersistent into this TKPreviewColors instance. } + procedure Assign(Source: TPersistent); override; + { Returns color for given index. } + property Color[Index: TKPreviewColorIndex]: TColor read GetColorEx write SetColorEx; + { Returns array of colors. } + property Colors: TKColorArray read FColors write SetColors; + published + { Specifies the paper background color. } + property Paper: TColor index ciPaper read GetColor write SetColor default cPaperDef; + { Specifies the color of the background around paper. } + property BkGnd: TColor index ciBkGnd read GetColor write SetColor default cBkGndDef; + { Specifies the color of the paper border. } + property Border: TColor index ciBorder read GetColor write SetColor default cBorderDef; + { Specifies the color of the paper border when the control has input focus. } + property SelectedBorder: TColor index ciSelectedBorder read GetColor write SetColor default cSelectedBorderDef; + end; + + { @abstract(Print preview control for the TKCustomControl component) } + TKPrintPreview = class(TKCustomControl) + private + FColors: TKPreviewColors; + FControl: TKCustomControl; + FMouseWheelAccumulator: Integer; + FPage: Integer; + FPageOld: Integer; + FPageSize: TPoint; + FExtent: TPoint; + FPageOffset: TPoint; + FScale: Integer; + FScaleMode: TKPreviewScaleMode; + FScrollExtent: TPoint; + FScrollPos: TPoint; + FScrollPosOld: TPoint; + FX: Integer; + FY: Integer; + FOnChanged: TKPreviewChangedEvent; + function GetCurrentScale: Integer; + function GetEndPage: Integer; + function GetStartPage: Integer; + procedure SetControl(Value: TKCustomControl); + procedure SetPage(Value: Integer); + procedure SetScale(Value: Integer); + procedure SetScaleMode(Value: TKPreviewScaleMode); + procedure WMEraseBkgnd(var Msg: TLMessage); message LM_ERASEBKGND; + procedure WMGetDlgCode(var Msg: TLMNoParams); message LM_GETDLGCODE; + procedure WMHScroll(var Msg: TLMHScroll); message LM_HSCROLL; + procedure WMKillFocus(var Msg: TLMKillFocus); message LM_KILLFOCUS; + procedure WMSetFocus(var Msg: TLMSetFocus); message LM_SETFOCUS; + procedure WMVScroll(var Msg: TLMVScroll); message LM_VSCROLL; + procedure SetColors(const Value: TKPreviewColors); + protected + { Initializes a scroll message handling. } + procedure BeginScrollWindow; + { Defines additional styles. } + procedure CreateParams(var Params: TCreateParams); override; + { Overriden method - handles mouse wheel messages. } + function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; + MousePos: TPoint): Boolean; override; + { Calls the ScrollWindowEx function to complete a scroll message. } + procedure EndScrollWindow; + { Returns current page rectangle inside of the window client area. } + function GetPageRect: TRect; + { Processes virtual key strokes. } + procedure KeyDown(var Key: Word; Shift: TShiftState); override; + { Processes scrollbar messages. +
    + Parameters: +
  • ScrollBar - scrollbar type from OS
  • +
  • ScrollCode - scrollbar action from OS
  • +
  • Delta - scrollbar position change
  • +
} + procedure ModifyScrollBar(ScrollBar, ScrollCode, Delta: Integer); + { Initializes drag&scroll functionality. } + procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; + { Performs drag&scroll functionality. } + procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; + { Finalizes drag&scroll functionality. } + procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; + { Notifies about associated TKCustomControl control removal. } + procedure Notification(AComponent: TComponent; Operation: TOperation); override; + { Paints paper and control shape. } + procedure Paint; override; + { Calls the @link(OnChanged) event. } + procedure Changed; + { Grants the input focus to the control when possible and the control has had none before. } + procedure SafeSetFocus; + { Updates mouse cursor. } + function SetMouseCursor(X, Y: Integer): Boolean; override; + { Updates page sizes and scrollbar ranges. } + procedure UpdateScrollRange; + { Updates the control size. } + procedure UpdateSize; override; + public + { Performs necessary initializations - default values to properties. } + constructor Create(AOwner: TComponent); override; + { Destroy instance... } + destructor Destroy; override; + { Shows first page for the given range. } + procedure FirstPage; + { Shows last page for the given range. } + procedure LastPage; + { Shows next page. } + procedure NextPage; + { Shows previous page. } + procedure PreviousPage; + { Updates the preview. } + procedure UpdatePreview; + { Returns the page scaling with regard to the @link(ScaleMode) property. } + property CurrentScale: Integer read GetCurrentScale; + { Returns the current page area rectangle in desktop pixels. } + property PageRect: TRect read GetPageRect; + { Returns the last page for the given range. } + property EndPage: Integer read GetEndPage; + { Returns the first page for the given range. } + property StartPage: Integer read GetStartPage; + published + { Inherited property - see Delphi help. } + property Align; + { Inherited property - see Delphi help. } + property Anchors; + { See TKCustomControl.@link(TKCustomControl.BorderStyle) for details. } + property BorderStyle; + { Inherited property - see Delphi help. } + property BorderWidth; + { Specifies all colors used by TKPrintPreview's default painting. } + property Colors: TKPreviewColors read FColors write SetColors; + { Inherited property - see Delphi help. } + property Constraints; + { Specifies the associated control. } + property Control: TKCustomControl read FControl write SetControl; + { Inherited property - see Delphi help. } + property DragCursor; + { Inherited property - see Delphi help. } + property DragKind; + { Inherited property - see Delphi help. } + property DragMode; + { Specifies the currently displayed page. } + property Page: Integer read FPage write SetPage default 1; + { Inherited property - see Delphi help. } + property ParentShowHint; + { Inherited property - see Delphi help. } + property PopupMenu; + { Specifies the user defined page scale - i.e. when ScaleMode = smScale. } + property Scale: Integer read FScale write SetScale default 100; + { Specifies the scale mode to display and scroll previewed pages. } + property ScaleMode: TKPreviewScaleMode read FScaleMode write SetScaleMode default smPageWidth; + { Inherited property - see Delphi help. } + property ShowHint; + { Inherited property - see Delphi help. } + property TabStop; + { Inherited property - see Delphi help. } + property TabOrder; + { Inherited property - see Delphi help. } + property Visible; + { Called whenever print preview is updated. } + property OnChanged: TKPreviewChangedEvent read FOnChanged write FOnChanged; + { Inherited property - see Delphi help. } + property OnClick; + { Inherited property - see Delphi help. } + property OnContextPopup; + { Inherited property - see Delphi help. } + property OnDblClick; + { Inherited property - see Delphi help. } + property OnDockDrop; + { Inherited property - see Delphi help. } + property OnDockOver; + { Inherited property - see Delphi help. } + property OnDragDrop; + { Inherited property - see Delphi help. } + property OnDragOver; + { Inherited property - see Delphi help. } + property OnEndDock; + { Inherited property - see Delphi help. } + property OnEndDrag; + { Inherited property - see Delphi help. } + property OnEnter; + { Inherited property - see Delphi help. } + property OnExit; + { Inherited property - see Delphi help. } + property OnGetSiteInfo; + { Inherited property - see Delphi help. } + property OnKeyDown; + { Inherited property - see Delphi help. } + property OnKeyPress; + { Inherited property - see Delphi help. } + property OnKeyUp; + { Inherited property - see Delphi help. } + property OnMouseDown; + { Inherited property - see Delphi help. } + property OnMouseMove; + { Inherited property - see Delphi help. } + property OnMouseUp; + { Inherited property - see Delphi help. } + property OnMouseWheel; + { Inherited property - see Delphi help. } + property OnMouseWheelDown; + { Inherited property - see Delphi help. } + property OnMouseWheelUp; + { Inherited property - see Delphi help. } + property OnResize; + { Inherited property - see Delphi help. } + property OnStartDock; + { Inherited property - see Delphi help. } + property OnStartDrag; + { Inherited property - see Delphi help. } + property OnUnDock; + end; + +{ Converts a value given in inches into a value given in specified units. +
    + Parameters: +
  • Units - measurement units for the output value
  • +
  • Value - input value to convert
  • +
} +function InchesToValue(Units: TKPrintUnits; Value: Double): Double; + +{ Converts value given in specified units into a value given in inches. +
    + Parameters: +
  • Units - measurement units for the input value
  • +
  • Value - input value to convert
  • +
} +function ValueToInches(Units: TKPrintUnits; Value: Double): Double; + +implementation + +uses + Math, Printers, KGraphics; + +const + cPreviewHorzBorder = 30; + cPreviewVertBorder = 30; + cPreviewShadowSize = 3; + +function InchesToValue(Units: TKPrintUnits; Value: Double): Double; +begin + case Units of + puMM: Result := Value * 25.4; + puCM: Result := Value * 2.54; + puHundredthInch: Result := Value * 100; + else + Result := Value; + end; +end; + +function ValueToInches(Units: TKPrintUnits; Value: Double): Double; +begin + case Units of + puMM: Result := Value / 25.4; + puCM: Result := Value / 2.54; + puHundredthInch: Result := Value / 100; + else + Result := Value; + end; +end; + +{ TKCustomControl } + +constructor TKCustomControl.Create(AOwner: TComponent); +begin + inherited; + BorderStyle := cBorderStyleDef; + FFlags := 0; + FMemoryCanvas := nil; + FMessages := nil; +{$IFNDEF COMPILER10_UP} + FMouseInClient := False; +{$ENDIF} + FPageSetup := nil; + FPreviewList := TList.Create; + FUpdateLock := 0; + FOnPrintNotify := nil; + FOnPrintPaint := nil; +end; + +destructor TKCustomControl.Destroy; +begin + inherited; + FMessages := nil; + FreeAndNil(FPreviewList); + FreeAndNil(FPageSetup); +end; + +procedure TKCustomControl.AddPreview(APreview: TKPrintPreview); +begin + if Assigned(APreview) then + FPreviewList.Add(APreview); +end; + +procedure TKCustomControl.AdjustPageSetup; +begin +end; + +procedure TKCustomControl.CancelMode; +begin +end; + +{$IFNDEF FPC} +procedure TKCustomControl.CMCancelMode(var Msg: TLMessage); +begin + inherited; + CancelMode; +end; + +procedure TKCustomControl.CMCtl3DChanged(var Msg: TLMessage); +begin + inherited; + RecreateWnd; +end; +{$ENDIF} + +procedure TKCustomControl.CMMouseLeave(var Msg: TLMessage); +begin + inherited; + try + MouseFormLeave; + except + end; +end; + +procedure TKCustomControl.CreateParams(var Params: TCreateParams); +begin + inherited; +{$IFNDEF FPC} + with Params do + begin + WindowClass.style := CS_DBLCLKS; + if BorderStyle = bsSingle then + if NewStyleControls and Ctl3D then + begin + Style := Style and not WS_BORDER; + ExStyle := ExStyle or WS_EX_CLIENTEDGE; + end + else + Style := Style or WS_BORDER; + end; +{$ENDIF} +end; + +{$IFDEF FPC} +procedure TKCustomControl.CreateWnd; +begin + inherited; + UpdateSize; +end; + +procedure TKCustomControl.DoOnChangeBounds; +begin + inherited; + UpdateSize; +end; +{$ENDIF} + +function TKCustomControl.Flag(AFlag: Cardinal): Boolean; +begin + Result := FFlags and AFlag <> 0; +end; + +procedure TKCustomControl.FlagAssign(AFlag: Cardinal; Value: Boolean); +begin + if Value then + FlagSet(AFlag) + else + FlagClear(AFlag); +end; + +procedure TKCustomControl.FlagClear(AFlag: Cardinal); +begin + FFlags := FFlags and not AFlag; +end; + +procedure TKCustomControl.FlagSet(AFlag: Cardinal); +begin + FFlags := FFlags or AFlag; +end; + +procedure TKCustomControl.FlagToggle(AFlag: Cardinal); +begin + FFlags := FFlags xor AFlag; +end; + +function TKCustomControl.GetCanPrint: Boolean; +begin + Result := PageSetup.CanPrint; +end; + +function TKCustomControl.GetPageSetup: TKPrintPageSetup; +begin + if not Assigned(FPageSetup) and not (csDestroying in ComponentState) then + begin + FPageSetup := TKPrintPageSetup.Create(Self); + AdjustPageSetup; + end; + if Assigned(FPageSetup) then + FPageSetup.Validate; + Result := FPageSetup; +end; + +function TKCustomControl.GetPageSetupAllocated: Boolean; +begin + Result := Assigned(FPageSetup); +end; + +function TKCustomControl.InternalGetSelAvail: Boolean; +begin + Result := False; +end; + +procedure TKCustomControl.InternalUnlockUpdate; +begin +end; + +procedure TKCustomControl.Invalidate; +begin + if UpdateUnlocked and HandleAllocated then + inherited; +end; + +procedure TKCustomControl.InvalidatePageSetup; +begin + if Assigned(FPageSetup) then + FPageSetup.Invalidate; +end; + +procedure TKCustomControl.InvalidateRectArea(const R: TRect); +begin + if UpdateUnlocked and HandleAllocated then + InvalidateRect(Handle, @R, False); +end; + +function TKCustomControl.IsThemed: Boolean; +begin + Result := True; +end; + +procedure TKCustomControl.KMLateUpdate(var Msg: TLMessage); +var + M: TLMessage; +begin + if MessagePeek(M) then + LateUpdate(M); +end; + +procedure TKCustomControl.LateUpdate(var Msg: TLMessage); +begin + case Msg.Msg of + LM_SIZE: UpdateSize; + end; +end; + +procedure TKCustomControl.LockUpdate; +begin + Inc(FUpdateLock); +end; + +procedure TKCustomControl.MeasurePages(var Info: TKPrintMeasureInfo); +begin +end; + +function TKCustomControl.MessagePeek(out Msg: TLMessage): Boolean; +var + ALen: Integer; +begin + ALen := Length(FMessages); + if ALen > 0 then + begin + Dec(ALen); + Msg := FMessages[ALen]; + SetLength(FMessages, ALen); + Result := True; + end else + Result := False; +end; + +procedure TKCustomControl.MessagePoke(const Msg: TLMessage); +var + ALen: Integer; +begin + ALen := Length(FMessages); + SetLength(FMessages, ALen + 1); + FMessages[ALen] := Msg; +end; + +function TKCustomControl.MessageSearch(MsgCode: Cardinal): Boolean; +var + I: Integer; +begin + Result := False; + for I := 0 to Length(FMessages) - 1 do + if FMessages[I].Msg = MsgCode then + begin + Result := True; + Exit; + end; +end; + +procedure TKCustomControl.MouseFormLeave; +begin +end; + +procedure TKCustomControl.MouseMove(Shift: TShiftState; X, Y: Integer); +begin + inherited; +{$IFNDEF COMPILER10_UP} + CallTrackMouseEvent(Self, FMouseInClient); +{$ENDIF} +{$IFDEF FPC} + if not MouseCapture then + SetMouseCursor(X, Y); +{$ENDIF} +end; + +procedure TKCustomControl.NotifyPreviews; +var + I: Integer; +begin + for I := 0 to FPreviewList.Count - 1 do + TKPrintPreview(FPreviewList[I]).UpdatePreview; +end; + +procedure TKCustomControl.Paint; +begin + PaintToCanvas(Canvas); + if Assigned(FMemoryCanvas) then + begin + {$IFDEF USE_WINAPI} + // this is the best method but does not work both on QT and GTK! + MoveWindowOrg(FMemoryCanvas.Handle, -FMemoryCanvasRect.Left, -FMemoryCanvasRect.Top); + try + PaintToCanvas(FMemoryCanvas); + finally + MoveWindowOrg(FMemoryCanvas.Handle, FMemoryCanvasRect.Left, FMemoryCanvasRect.Top); + end; + {$ELSE} + FMemoryCanvas.CopyRect(Rect(0, 0, FMemoryCanvasRect.Right - FMemoryCanvasRect.Left, + FMemoryCanvasRect.Bottom - FMemoryCanvasRect.Top), Canvas, FMemoryCanvasRect); + {$ENDIF} + FMemoryCanvas := nil; + end; +end; + +procedure TKCustomControl.PostLateUpdate(const Msg: TLMessage; + IfNotExists: Boolean); +begin + if HandleAllocated then + begin + if not IfNotExists or not MessageSearch(Msg.Msg) then + MessagePoke(Msg); + PostMessage(Handle, KM_LATEUPDATE, 0, 0); + end; +end; + +procedure TKCustomControl.PrintNotify(Status: TKPrintStatus; var Abort: Boolean); +begin + if Assigned(FOnPrintNotify) then + FOnPrintNotify(Self, Status, Abort); +end; + +procedure TKCustomControl.PrintPaint; +begin + if Assigned(FOnPrintPaint) then + FOnPrintPaint(Self); +end; + +procedure TKCustomControl.PrintOut; +begin + GetPageSetup.PrintOut; +end; + +procedure TKCustomControl.PaintPage; +begin +end; + +procedure TKCustomControl.RemovePreview(APreview: TKPrintPreview); +begin + if Assigned(FPreviewList) and (FPreviewList.IndexOf(APreview) >= 0) then + FPreviewList.Remove(APreview); +end; + +{$IFNDEF FPC} +procedure TKCustomControl.SetBorderStyle(Value: TBorderStyle); +begin + if FBorderStyle <> Value then + begin + FBorderStyle := Value; + RecreateWnd; + end; +end; +{$ENDIF} + +function TKCustomControl.SetMouseCursor(X, Y: Integer): Boolean; +begin + Result := False; +end; + +procedure TKCustomControl.SetPageSetup(Value: TKPrintPageSetup); +begin + if Value <> FPageSetup then + GetPageSetup.Assign(Value); +end; + +procedure TKCustomControl.UnlockUpdate; +begin + if FUpdateLock > 0 then + begin + Dec(FUpdateLock); + if FUpdateLock = 0 then + InternalUnlockUpdate; + end; +end; + +procedure TKCustomControl.UpdateSize; +begin +end; + +function TKCustomControl.UpdateUnlocked: Boolean; +begin + Result := FUpdateLock = 0; +end; + +{$IFNDEF FPC} +procedure TKCustomControl.WMCancelMode(var Msg: TWMCancelMode); +begin + inherited; + CancelMode; +end; +{$ENDIF} + +{$IFNDEF COMPILER10_UP} +procedure TKCustomControl.WMMouseLeave(var Msg: TLMessage); +begin + { this is because of CM_MOUSELEAVE is not sent if mouse has left client area + and entered any of the standard control scrollbars. This behavior has been + fixed via TrackMouseEvent in BDS 2006. } + inherited; + FMouseInClient := False; + Perform(CM_MOUSELEAVE, 0, 0); +end; +{$ENDIF} + +{$IFNDEF FPC} +procedure TKCustomControl.WMNCPaint(var Msg: TWMNCPaint); +{$IFDEF USE_THEMES} +var + R: TRect; + ExStyle: Integer; + TempRgn: HRGN; + BorderWidth, + BorderHeight: Integer; +{$ENDIF} +begin +{$IFDEF USE_THEMES} + with ThemeServices do if IsThemed and ThemesEnabled then + begin + // If OS themes are enabled and the client edge border is set for the window then prevent the default window proc + // from painting the old border to avoid flickering. + ExStyle := GetWindowLong(Handle, GWL_EXSTYLE); + if (ExStyle and WS_EX_CLIENTEDGE) <> 0 then + begin + GetWindowRect(Handle, R); + // Determine width of the client edge. + BorderWidth := GetSystemMetrics(SM_CXEDGE); + BorderHeight := GetSystemMetrics(SM_CYEDGE); + InflateRect(R, -BorderWidth, -BorderHeight); + TempRgn := CreateRectRgnIndirect(R); + // Exclude the border from the message region if there is one. Otherwise just use the inflated + // window area region. + if Msg.Rgn <> 1 then + CombineRgn(TempRgn, Msg.Rgn, TempRgn, RGN_AND); + DefWindowProc(Handle, Msg.Msg, Integer(TempRgn), 0); + DeleteObject(TempRgn); + PaintBorder(Self, True); + end else + inherited; + end else +{$ENDIF} + inherited; +end; + +procedure TKCustomControl.WMSetCursor(var Msg: TWMSetCursor); +var + MousePt: TPoint; +begin + if (Msg.HitTest = HTCLIENT) and (Msg.CursorWnd = Handle) then + begin + MousePt := ScreenToClient(Mouse.CursorPos); + if SetMouseCursor(MousePt.X, MousePt.Y) then + Msg.Result := 1 + else + inherited + end else + inherited; +end; +{$ENDIF} + +procedure TKCustomControl.WMSize(var Msg: TLMSize); +begin + inherited; + PostLateUpdate(FillMessage(LM_SIZE, 0, 0), True); +end; + +{$IFNDEF FPC} +{$IFDEF USE_THEMES} +procedure TKCustomControl.WMThemeChanged(var Msg: TLMessage); +begin + if IsThemed then + begin + inherited; + ThemeServices.UpdateThemes; + RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_VALIDATE or RDW_FRAME); + end; +end; +{$ENDIF} +{$ENDIF} + +{ TKPrintPageSetup } + +constructor TKPrintPageSetup.Create(AControl: TKCustomControl); +begin + inherited Create; + FActive := False; + FCanvas := nil; + FControl := AControl; + FCopies := cCopiesDef; + FCurrentCopy := 0; + FCurrentPage := 0; + FCurrentScale := 0; + FDesktopPixelsPerInchX := 0; + FDesktopPixelsPerInchY := 0; + FEndPage := 0; + FFooterSpace := 0; + FHeaderSpace := 0; + FHorzPageCount := 0; + FIsValid := False; + FMarginBottom := cMarginBottomDef; + FMarginLeft := cMarginLeftDef; + FMarginRight := cMarginRightDef; + FMarginTop := cMarginTopDef; + FOptions := cOptionsDef; + FOutlineHeight := 0; + FOutlineWidth := 0; + FPageCount := 0; + FPageHeight := 0; + FPageWidth := 0; + FPaintAreaHeight := 0; + FPaintAreaWidth := 0; + FPreviewing := False; + FPrinterFooterSpace := 0; + FPrinterHeaderSpace := 0; + FPrinterMarginBottom := 0; + FPrinterMarginLeft := 0; + FPrinterMarginLeftMirrored := 0; + FPrinterMarginRight := 0; + FPrinterMarginRightMirrored := 0; + FPrinterMarginTop := 0; + FPrinterName := ''; + FPrinterPixelsPerInchX := 0; + FPrinterPixelsPerInchY := 0; + FPrintingMapped := True; + FRange := cRangeDef; + FStartPage := 0; + FScale := cScaleDef; + FTitle := ''; + FUnits := cUnitsDef; + FUpdateLock := 0; + FValidating := False; + FVertPageCount := 0; +end; + +function TKPrintPageSetup.GetCanPrint: Boolean; +begin + Result := Assigned(FControl) and (FPageCount > 0) and (Printer.Printers.Count > 0); +end; + +function TKPrintPageSetup.GetSelAvail: Boolean; +begin + if Assigned(FControl) then + Result := FControl.InternalGetSelAvail + else + Result := False; +end; + +procedure TKPrintPageSetup.AfterUnitsChange; +begin + FFooterSpace := InchesToValue(FUnits, FFooterSpace); + FHeaderSpace := InchesToValue(FUnits, FHeaderSpace); + FMarginBottom := InchesToValue(FUnits, FMarginBottom); + FMarginLeft := InchesToValue(FUnits, FMarginLeft); + FMarginRight := InchesToValue(FUnits, FMarginRight); + FMarginTop := InchesToValue(FUnits, FMarginTop); +end; + +procedure TKPrintPageSetup.Assign(Source: TPersistent); +begin + if Source is TKPrintPageSetup then + begin + LockUpdate; + try + Copies := TKPrintPageSetup(Source).Copies; + EndPage := TKPrintPageSetup(Source).EndPage; + FooterSpace := TKPrintPageSetup(Source).FooterSpace; + HeaderSpace := TKPrintPageSetup(Source).HeaderSpace; + MarginBottom := TKPrintPageSetup(Source).MarginBottom; + MarginLeft := TKPrintPageSetup(Source).MarginLeft; + MarginRight := TKPrintPageSetup(Source).MarginRight; + MarginTop := TKPrintPageSetup(Source).MarginTop; + Options := TKPrintPageSetup(Source).Options; + PrinterName := TKPrintPageSetup(Source).PrinterName; + Range := TKPrintPageSetup(Source).Range; + StartPage := TKPrintPageSetup(Source).StartPage; + Scale := TKPrintPageSetup(Source).Scale; + Title := TKPrintPageSetup(Source).Title; + Units := TKPrintPageSetup(Source).Units; + finally + UnlockUpdate; + end; + end; +end; + +procedure TKPrintPageSetup.BeforeUnitsChange; +begin + FFooterSpace := ValueToInches(FUnits, FFooterSpace); + FHeaderSpace := ValueToInches(FUnits, FHeaderSpace); + FMarginBottom := ValueToInches(FUnits, FMarginBottom); + FMarginLeft := ValueToInches(FUnits, FMarginLeft); + FMarginRight := ValueToInches(FUnits, FMarginRight); + FMarginTop := ValueToInches(FUnits, FMarginTop); +end; + +function TKPrintPageSetup.HMap(Value: Integer): Integer; +begin + Result := MulDiv(Value, FPrinterPixelsPerInchX, FDesktopPixelsPerInchX); +end; + +procedure TKPrintPageSetup.Invalidate; +begin + FIsValid := False; +end; + +procedure TKPrintPageSetup.LockUpdate; +begin + Inc(FUpdateLock); +end; + +procedure TKPrintPageSetup.PaintPageToPreview; +var + PaperWidth, PaperHeight, SaveIndex: Integer; + R, PageRect: TRect; +begin + if UpdateUnlocked and Assigned(FControl) then + begin + FCanvas := APreview.Canvas; + FActive := True; + FPreviewing := True; + try + FCurrentCopy := 1; + FCurrentPage := APreview.Page; + if (poMirrorMargins in FOptions) and (FCurrentPage and 1 <> 0) then + begin + FPrinterMarginLeftMirrored := FPrinterMarginRight; + FPrinterMarginRightMirrored := FPrinterMarginLeft; + end else + begin + FPrinterMarginLeftMirrored := FPrinterMarginLeft; + FPrinterMarginRightMirrored := FPrinterMarginRight; + end; + R := APreview.PageRect; + PaperWidth := R.Right - R.Left; + PaperHeight := R.Bottom - R.Top; + SaveIndex := SaveDC(FCanvas.Handle); + try + // change the canvas mapping mode to scale the page outline + CanvasSetOffset(FCanvas, + R.Left + MulDiv(FPrinterMarginLeftMirrored, PaperWidth, FPageWidth), + R.Top + MulDiv(FPrinterMarginTop + FPrinterHeaderSpace, PaperHeight, FPageHeight)); + if FPrintingMapped then + CanvasSetScale(FCanvas, Round(PaperWidth * FCurrentScale), Round(PaperHeight * FCurrentScale), + MulDiv(FPageWidth, FDesktopPixelsPerInchX, FPrinterPixelsPerInchX), + MulDiv(FPageHeight, FDesktopPixelsPerInchY, FPrinterPixelsPerInchY)) + else + CanvasSetScale(FCanvas, PaperWidth, PaperHeight, FPageWidth, FPageHeight); + FControl.PaintPage; + finally + RestoreDC(FCanvas.Handle, SaveIndex); + end; + SaveIndex := SaveDC(FCanvas.Handle); + try + CanvasSetOffset(FCanvas, R.Left, R.Top); + CanvasSetScale(FCanvas, PaperWidth, PaperHeight, FPageWidth, FPageHeight); + PageRect := Rect(0, 0, FPageWidth, FPageHeight); + TranslateRectToDevice(FCanvas.Handle, PageRect); + SelectClipRect(FCanvas.Handle, PageRect); + FControl.PrintPaint; + finally + RestoreDC(FCanvas.Handle, SaveIndex); + end; + SaveIndex := SaveDC(FCanvas.Handle); + try + CanvasSetOffset(FCanvas, R.Left, R.Top); + CanvasSetScale(FCanvas, PaperWidth, PaperHeight, FPageWidth, FPageHeight); + PageRect := Rect(0, 0, FPageWidth, FPageHeight); + TranslateRectToDevice(FCanvas.Handle, PageRect); + SelectClipRect(FCanvas.Handle, PageRect); + PrintTitle; + PrintPageNumber(FCurrentPage); + finally + RestoreDC(FCanvas.Handle, SaveIndex); + end; + finally + FActive := False; + FPreviewing := False; + FCanvas := nil; + end; + end; +end; + +procedure TKPrintPageSetup.PrintPageNumber(Value: Integer); +var + S: string; +begin + if poPageNumbers in FOptions then + begin + FCanvas.Brush.Style := bsClear; + FCanvas.Font.Color := clBlack; + FCanvas.Font.Height := 1; + FCanvas.Font.Height := VMap(16); + FCanvas.Font.Name := 'Arial'; + FCanvas.Font.Pitch := fpDefault; + FCanvas.Font.Style := [fsBold]; + S := Format('- %d -', [Value]); + FCanvas.TextOut(FPrinterMarginLeftMirrored + (FPageWidth - FPrinterMarginLeft - FPrinterMarginRight - FCanvas.TextWidth(S)) div 2, + FPageHeight - FPrinterMarginBottom + VMap(5), S); + end; +end; + +procedure TKPrintPageSetup.PrintTitle; +begin + if poTitle in FOptions then + begin + FCanvas.Brush.Style := bsClear; + FCanvas.Font.Color := clBlack; + FCanvas.Font.Height := 1; + FCanvas.Font.Height := VMap(16); + FCanvas.Font.Name := 'Arial'; + FCanvas.Font.Pitch := fpDefault; + FCanvas.Font.Style := [fsBold]; + FCanvas.TextOut(FPrinterMarginLeftMirrored, FPrinterMarginTop - VMap(36), Title); + FCanvas.Brush.Style := bsSolid; + FCanvas.Brush.Color := clBlack; + FCanvas.FillRect(Rect(FPrinterMarginLeftMirrored, FPrinterMarginTop - VMap(14), FPageWidth - FPrinterMarginRight, FPrinterMarginTop - VMap(12))); + end; +end; + +procedure TKPrintPageSetup.PrintOut; + + function DoPrint: Boolean; + var + SaveIndex: Integer; + PageRect: TRect; + begin + Result := False; + if (poMirrorMargins in FOptions) and (FCurrentPage and 1 <> 0) then + begin + FPrinterMarginLeftMirrored := FPrinterMarginRight; + FPrinterMarginRightMirrored := FPrinterMarginLeft; + end else + begin + FPrinterMarginLeftMirrored := FPrinterMarginLeft; + FPrinterMarginRightMirrored := FPrinterMarginRight; + end; + SaveIndex := SaveDC(FCanvas.Handle); + try + CanvasSetOffset(FCanvas, FPrinterMarginLeftMirrored, FPrinterMarginTop + FPrinterHeaderSpace); + if FPrintingMapped then + begin + // change the canvas mapping mode to scale the page outline + CanvasSetScale(FCanvas, Round(FPageWidth * FCurrentScale), Round(FPageHeight * FCurrentScale), + MulDiv(FPageWidth, FDesktopPixelsPerInchX, FPrinterPixelsPerInchX), + MulDiv(FPageHeight, FDesktopPixelsPerInchY, FPrinterPixelsPerInchY)); + end else + CanvasResetScale(FCanvas); + FControl.PaintPage; + finally + RestoreDC(FCanvas.Handle, SaveIndex); + end; + SaveIndex := SaveDC(FCanvas.Handle); + try + CanvasResetScale(FCanvas); + PageRect := Rect(0, 0, FPageWidth, FPageHeight); + TranslateRectToDevice(FCanvas.Handle, PageRect); + SelectClipRect(FCanvas.Handle, PageRect); + FControl.PrintPaint; + finally + RestoreDC(FCanvas.Handle, SaveIndex); + end; + SaveIndex := SaveDC(FCanvas.Handle); + try + CanvasResetScale(FCanvas); + PageRect := Rect(0, 0, FPageWidth, FPageHeight); + TranslateRectToDevice(FCanvas.Handle, PageRect); + SelectClipRect(FCanvas.Handle, PageRect); + PrintTitle; + PrintPageNumber(FCurrentPage); + finally + RestoreDC(FCanvas.Handle, SaveIndex); + end; + FControl.PrintNotify(epsNewPage, Result); + if ((FCurrentPage < FEndPage) or (FCurrentCopy < FCopies)) and not Result then + Printer.NewPage; + end; + +var + I, J: Integer; + AbortPrint: Boolean; +{ Orientation: TPrinterOrientation; + PaperSize: TPaperSize; + APageWidth, ApageHeight, APaperWidth, APaperHeight: Integer; + PrinterType: TPrinterType; + APaperRect: TPaperRect;} +begin + if UpdateUnlocked and Assigned(FControl) then + begin + UpdateSettings; + if FPageCount > 0 then + begin + AbortPrint := False; + FCanvas := Printer.Canvas; + Printer.Title := FTitle; + Printer.Copies := 1; +{ PrinterType := Printer.PrinterType; + APageWidth := Printer.PageWidth; + APageHeight := Printer.PageHeight; + APaperRect := Printer.PaperSize.PaperRect; + Orientation := Printer.Orientation;} + Printer.BeginDoc; + FActive := True; + try + FControl.PrintNotify(epsBegin, AbortPrint); +{ Printer.Canvas.Font.Name := 'Arial'; + Printer.Canvas.Font.color := clBlack; + Printer.Canvas.Font.height := 100; + Printer.Canvas.TextOut(200, 200, 'hello!');} + if not AbortPrint then + begin + if poCollate in FOptions then + for I := 1 to FCopies do + begin + FCurrentCopy := I; + for J := FStartPage to FEndPage do + begin + FCurrentPage := J; + AbortPrint := DoPrint; + if AbortPrint then Break; + end; + if AbortPrint then Break; + end + else + for J := FStartPage to FEndPage do + begin + FCurrentPage := J; + for I := 1 to FCopies do + begin + FCurrentCopy := I; + AbortPrint := DoPrint; + if AbortPrint then Break; + end; + if AbortPrint then Break; + end + end; + FCurrentPage := 0; + FCurrentCopy := 0; + FControl.PrintNotify(epsEnd, AbortPrint); + finally + FActive := False; + Printer.EndDoc; + FCanvas := nil; + end; + end; + end; +end; + +procedure TKPrintPageSetup.SetCopies(Value: Integer); +begin + if FActive then Exit; + if Value <> FCopies then + begin + FCopies := Value; + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.SetEndPage(Value: Integer); +begin + if FActive then Exit; + if Value <> FEndPage then + begin + FEndPage := Value; + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.SetFooterSpace(Value: Double); +begin + if FActive then Exit; + if Value <> FFooterSpace then + begin + FFooterSpace := Value; + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.SetHeaderSpace(Value: Double); +begin + if FActive then Exit; + if Value <> FHeaderSpace then + begin + FHeaderSpace := Value; + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.SetMarginBottom(Value: Double); +begin + if FActive then Exit; + if Value <> FMarginBottom then + begin + FMarginBottom := Value; + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.SetMarginLeft(Value: Double); +begin + if FActive then Exit; + if Value <> FMarginLeft then + begin + FMarginLeft := Value; + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.SetMarginRight(Value: Double); +begin + if FActive then Exit; + if Value <> FMarginRight then + begin + FMarginRight := Value; + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.SetMarginTop(Value: Double); +begin + if FActive then Exit; + if Value <> FMarginTop then + begin + FMarginTop := Value; + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.SetOptions(Value: TKPrintOptions); +begin + if FActive then Exit; + if Value <> FOptions then + begin + FOptions := Value; + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.SetPrinterName(const Value: string); +begin + if FActive then Exit; + if Value <> FPrinterName then + begin + FPrinterName := Value; + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.SetPrintingMapped(Value: Boolean); +begin + if FActive then Exit; + if Value <> FPrintingMapped then + begin + FPrintingMapped := Value; + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.SetRange(Value: TKPrintRange); +begin + if FActive then Exit; + if Value <> FRange then + begin + FRange := Value; + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.SetScale(Value: Integer); +begin + if FActive then Exit; + if Value <> FScale then + begin + FScale := Value; + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.SetStartPage(Value: Integer); +begin + if FActive then Exit; + if Value <> FStartPage then + begin + FStartPage := Value; + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.SetUnits(Value: TKPrintUnits); +begin + if FActive then Exit; + if Value <> FUnits then + begin + BeforeUnitsChange; + FUnits := Value; + AfterUnitsChange; + end; +end; + +procedure TKPrintPageSetup.UnlockUpdate; +begin + if FUpdateLock > 0 then + begin + Dec(FUpdateLock); + UpdateSettings; + end; +end; + +procedure TKPrintPageSetup.UpdateSettings; +var + I, PixelsPerInchX, PixelsPerInchY: Integer; + D: Double; + DC: HDC; + Info: TKPrintMeasureInfo; +begin + if UpdateUnlocked and not FActive and not FValidating then + begin + FValidating := True; + try + Printer.Refresh; + I := Printer.Printers.IndexOf(FPrinterName); + if I >= 0 then + Printer.PrinterIndex := I; + // limit copies and Scale + FCopies := MinMax(FCopies, cCopiesMin, cCopiesMax); + FScale := MinMax(FScale, cScaleMin, cScaleMax); + // get metrics for the desktop + DC := GetDC(0); + try + FDesktopPixelsPerInchX := GetDeviceCaps(DC, LOGPIXELSX); + FDesktopPixelsPerInchY := GetDeviceCaps(DC, LOGPIXELSY); + finally + ReleaseDC(0, DC); + end; + // get metrics for the printer + if Printer.Printers.Count > 0 then + begin + FPageWidth := Printer.PageWidth; + FPageHeight := Printer.PageHeight; + {$IFDEF FPC} + FPrinterPixelsPerInchX := Printer.XDPI; + FPrinterPixelsPerInchY := Printer.YDPI; + {$ELSE} + FPrinterPixelsPerInchX := GetDeviceCaps(Printer.Handle, LOGPIXELSX); + FPrinterPixelsPerInchY := GetDeviceCaps(Printer.Handle, LOGPIXELSY); + {$ENDIF} + end else + begin + // fake printer metrics if no printer is installed + FPageWidth := 2360; + FPageHeight := 3400; + FPrinterPixelsPerInchX := 300; + FPrinterPixelsPerInchY := 300; + end; + // decide how to outline extent + if FPrintingMapped then + begin + PixelsPerInchX := FDesktopPixelsPerInchX; + PixelsPerInchY := FDesktopPixelsPerInchY; + end else + begin + PixelsPerInchX := FPrinterPixelsPerInchX; + PixelsPerInchY := FPrinterPixelsPerInchY; + end; + // limit and convert margins + D := FPageWidth * 0.4; // 40% of the page + FPrinterMarginLeft := Round(MinMax(ValueToInches(FUnits, FMarginLeft) * FPrinterPixelsPerInchX, 0, D)); + FPrinterMarginLeftMirrored := FPrinterMarginLeft; + FMarginLeft := InchesToValue(FUnits, FPrinterMarginLeft / FPrinterPixelsPerInchX); + FPrinterMarginRight := Round(MinMax(ValueToInches(FUnits, FMarginRight) * FPrinterPixelsPerInchX, 0, D)); + FPrinterMarginRightMirrored := FPrinterMarginRight; + FMarginRight := InchesToValue(FUnits, FPrinterMarginRight / FPrinterPixelsPerInchX); + D := FPageHeight * 0.4; // 40% of the page + FPrinterMarginTop := Round(MinMax(ValueToInches(FUnits, FMarginTop) * FPrinterPixelsPerInchY, 0, D)); + FMarginTop := InchesToValue(FUnits, FPrinterMarginTop / FPrinterPixelsPerInchY); + FPrinterMarginBottom := Round(MinMax(ValueToInches(FUnits, FMarginBottom) * FPrinterPixelsPerInchY, 0, D)); + FMarginBottom := InchesToValue(FUnits, FPrinterMarginBottom / FPrinterPixelsPerInchY); + // limit and convert header and footer space + FPrinterHeaderSpace := Round(MinMax(ValueToInches(FUnits, Max(FHeaderSpace, 0)) * FPrinterPixelsPerInchY, 0, D - FPrinterMarginTop)); + FHeaderSpace := InchesToValue(FUnits, FPrinterHeaderSpace / FPrinterPixelsPerInchY); + FPrinterFooterSpace := Round(MinMax(ValueToInches(FUnits, Max(FFooterSpace, 0)) * FPrinterPixelsPerInchY, 0, D - FPrinterMarginBottom)); + FFooterSpace := InchesToValue(FUnits, FPrinterFooterSpace / FPrinterPixelsPerInchY); + // paint area extent + FPaintAreaHeight := MulDiv(FPageHeight - FPrinterMarginTop - FPrinterMarginBottom - FPrinterHeaderSpace - FPrinterFooterSpace, PixelsPerInchY, FPrinterPixelsPerInchY); + FPaintAreaWidth := MulDiv(FPageWidth - FPrinterMarginLeft - FPrinterMarginRight, PixelsPerInchX, FPrinterPixelsPerInchX); + // default horizontal scaling + FCurrentScale := FScale / 100; + // default page/copy info + FCurrentCopy := 0; + FCurrentPage := 0; + // measured data + if Assigned(FControl) then + begin + FillChar(Info, SizeOf(TKPrintMeasureInfo), 0); + FControl.MeasurePages(Info); + FOutlineWidth := Info.OutlineWidth; + FOutlineHeight := Info.OutlineHeight; + FHorzPageCount := Info.HorzPageCount; + FVertPageCount := Info.VertPageCount; + FPageCount := Info.PageCount; + if FPageCount > 0 then + begin + // update horizontal scaling + if (poFitToPage in FOptions) and (FOutlineWidth > 0) then + FCurrentScale := FPaintAreaWidth / FOutlineWidth; + // limit start and end page + case FRange of + prAll, prSelectedOnly: + begin + FStartPage := 1; + FEndPage := FPageCount; + end; + prRange: + begin + FEndPage := MinMax(FEndPage, 1, FPageCount); + FStartPage := MinMax(FStartPage, 1, FEndPage); + end; + end; + end; + // notify all previews/ force their repainting + FControl.NotifyPreviews; + end else + begin + FOutlineWidth := 0; + FOutlineHeight := 0; + FHorzPageCount := 0; + FVertPageCount := 0; + FPageCount := 0; + FEndPage := 0; + FStartPage := 0; + end; + FIsValid := True; + finally + FValidating := False; + end; + end; +end; + +function TKPrintPageSetup.UpdateUnlocked: Boolean; +begin + Result := FUpdateLock = 0; +end; + +procedure TKPrintPageSetup.Validate; +begin + if not FIsValid and not FValidating then + UpdateSettings; +end; + +function TKPrintPageSetup.VMap(Value: Integer): Integer; +begin + Result := MulDiv(Value, FPrinterPixelsPerInchY, FDesktopPixelsPerInchY); +end; + +{ TKPreviewColors } + +constructor TKPreviewColors.Create(APreview: TKPrintPreview); +begin + inherited Create; + FPreview := APreview; + Initialize; +end; + +procedure TKPreviewColors.Assign(Source: TPersistent); +begin + inherited; + if Source is TKPreviewColors then + begin + Colors := TKPreviewColors(Source).Colors; + FPreview.Invalidate; + end +end; + +function TKPreviewColors.GetColor(Index: TKPreviewColorIndex): TColor; +begin + Result := InternalGetColor(Index); +end; + +function TKPreviewColors.GetColorEx(Index: TKPreviewColorIndex): TColor; +begin + Result := FColors[Index]; +end; + +procedure TKPreviewColors.Initialize; +begin + SetLength(FColors, ciPreviewColorsMax + 1); + FColors[ciPaper] := cPaperDef; + FColors[ciBkGnd] := cBkGndDef; + FColors[ciBorder] := cBorderDef; + FColors[ciSelectedBorder] := cSelectedBorderDef; +end; + +function TKPreviewColors.InternalGetColor(Index: TKPreviewColorIndex): TColor; +begin + Result := FColors[Index]; +end; + +procedure TKPreviewColors.InternalSetColor(Index: TKPreviewColorIndex; Value: TColor); +begin + if FColors[Index] <> Value then + begin + FColors[Index] := Value; + if not (csLoading in FPreview.ComponentState) then + FPreview.Invalidate; + end; +end; + +procedure TKPreviewColors.SetColor(Index: TKPreviewColorIndex; Value: TColor); +begin + InternalSetColor(Index, Value); +end; + +procedure TKPreviewColors.SetColorEx(Index: TKPreviewColorIndex; Value: TColor); +begin + FColors[Index] := Value; +end; + +procedure TKPreviewColors.SetColors(const Value: TKColorArray); +var + I: Integer; +begin + for I := 0 to Min(Length(FColors), Length(Value)) - 1 do + FColors[I] := Value[I]; +end; + +{ TKPrintPreview } + +constructor TKPrintPreview.Create(AOwner: TComponent); +begin + inherited; + FColors := TKPreviewColors.Create(Self); + FControl := nil; + FMouseWheelAccumulator := 0; + FPage := 1; + FPageSize := Point(0, 0); + FScale := 100; + FScaleMode := smPageWidth; + FOnChanged := nil; + LoadCustomCursor(crDragHandFree, 'KPREVIEW_CURSOR_HAND_FREE'); + LoadCustomCursor(crDragHandGrip, 'KPREVIEW_CURSOR_HAND_GRIP'); + Width := 300; + Height := 200; +end; + +destructor TKPrintPreview.Destroy; +begin + if Assigned(FControl) then + FControl.RemovePreview(Self); + inherited; + FColors.Free; +end; + +procedure TKPrintPreview.BeginScrollWindow; +begin + FPageOld := FPage; + FScrollPosOld := FScrollPos; +end; + +procedure TKPrintPreview.CreateParams(var Params: TCreateParams); +begin + inherited; + with Params do + Style := Style or WS_HSCROLL or WS_VSCROLL; +end; + +function TKPrintPreview.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; + MousePos: TPoint): Boolean; +const + cWheelDivisor = 120; +var + Delta, WheelClicks: Integer; +begin + Result := inherited DoMouseWheel(Shift, WheelDelta, MousePos); + if not Result then + begin + if ssCtrl in Shift then + begin + if FScaleMode = smWholePage then Delta := 10 else Delta := ClientHeight; + end else + if FScaleMode = smWholePage then Delta := 1 else Delta := ClientHeight div 10; + Inc(FMouseWheelAccumulator, WheelDelta); + WheelClicks := FMouseWheelAccumulator div cWheelDivisor; + FMouseWheelAccumulator := FMouseWheelAccumulator mod cWheelDivisor; + BeginScrollWindow; + ModifyScrollBar(SB_VERT, -1, -WheelClicks * Delta); + EndScrollWindow; + Result := True; + end; +end; + +procedure TKPrintPreview.EndScrollWindow; +begin + if (FPage <> FPageOld) then + Invalidate + else if (FScrollPos.X <> FScrollPosOld.X) or (FScrollPos.Y <> FScrollPosOld.Y) then + begin + ScrollWindowEx(Handle, FScrollPosOld.X - FScrollPos.X, FScrollPosOld.Y - FScrollPos.Y, + nil, nil, 0, nil, SW_INVALIDATE); + end; +end; + +procedure TKPrintPreview.FirstPage; +begin + Page := StartPage; +end; + +function TKPrintPreview.GetCurrentScale: Integer; +begin + if Assigned(FControl) then + Result := MulDiv(FPageSize.X, 100, MulDiv(FControl.PageSetup.PageWidth, 300, FControl.PageSetup.PrinterPixelsPerInchX)) + else + Result := FScale; +end; + +function TKPrintPreview.GetEndPage: Integer; +begin + if Assigned(FControl) then + begin + Result := FControl.PageSetup.EndPage; + if Result = 0 then + begin + FControl.PageSetup.UpdateSettings; + Result := FControl.PageSetup.EndPage + end; + end else + Result := 0; +end; + +function TKPrintPreview.GetPageRect: TRect; +begin + with Result do + begin + Left := FPageOffset.X - FScrollPos.X; + if FScaleMode = smWholePage then + Top := FPageOffset.Y + else + Top := FPageOffset.Y - FScrollPos.Y; + Right := Left + FPageSize.X; + Bottom := Top + FPageSize.Y; + end; +end; + +function TKPrintPreview.GetStartPage: Integer; +begin + if Assigned(FControl) then + begin + Result := FControl.PageSetup.StartPage; + if Result = 0 then + begin + FControl.PageSetup.UpdateSettings; + Result := FControl.PageSetup.StartPage + end; + end else + Result := 0; +end; + +procedure TKPrintPreview.KeyDown(var Key: Word; Shift: TShiftState); +var + DeltaX, DeltaY, LineX, PageY: Integer; + NoAlt, NoAltCtrl: Boolean; +begin + NoAlt := Shift * [ssAlt] = []; + NoAltCtrl := Shift * [ssAlt, ssCtrl] = []; + DeltaX := 0; + DeltaY := 0; + LineX := ClientWidth div 10; + PageY := ClientHeight; + case Key of + VK_UP: + if NoAltCtrl then + begin + if FScaleMode = smWholePage then + PreviousPage + else + DeltaY := -PageY div 10; + end; + VK_DOWN: + if NoAltCtrl then + begin + if FScaleMode = smWholePage then + NextPage + else + DeltaY := PageY div 10; + end; + VK_PRIOR: + if NoAltCtrl then + begin + if FScaleMode = smWholePage then + PreviousPage + else + DeltaY := -PageY; + end; + VK_NEXT: + if NoAltCtrl then + begin + if FScaleMode = smWholePage then + NextPage + else + DeltaY := PageY; + end; + VK_LEFT: if NoAltCtrl then DeltaX := -LineX; + VK_RIGHT: if NoAltCtrl then DeltaX := LineX; + VK_HOME: + if NoAlt then + begin + if ssCtrl in Shift then + FirstPage + else + DeltaX := -FScrollPos.X; + end; + VK_END: + if NoAlt then + begin + if ssCtrl in Shift then + LastPage + else + DeltaX := FScrollExtent.X - FScrollPos.X; + end; + end; + if (DeltaX <> 0) or (DeltaY <> 0) then + begin + BeginScrollWindow; + if DeltaX <> 0 then + ModifyScrollBar(SB_HORZ, -1, DeltaX); + if DeltaY <> 0 then + ModifyScrollBar(SB_VERT, -1, DeltaY); + EndScrollWindow; + end; +end; + +procedure TKPrintPreview.LastPage; +begin + Page := EndPage; +end; + +procedure TKPrintPreview.ModifyScrollBar(ScrollBar, ScrollCode, Delta: Integer); +var + I, AEndPage: Integer; + Divisor: Cardinal; + PPos, PExtent: PInteger; + SI: TScrollInfo; +begin + Divisor := 10; + if ScrollBar = SB_HORZ then + begin + PPos := @FScrollPos.X; + PExtent := @FScrollExtent.X; + end else + begin + if FScaleMode = smWholePage then + begin + PPos := @FPage; + AEndPage := EndPage; + PExtent := @AEndPage; + Divisor := 1; + end else + begin + PPos := @FScrollPos.Y; + PExtent := @FScrollExtent.Y; + end; + end; + if PExtent^ > 0 then + begin + SI.cbSize := SizeOf(TScrollInfo); + SI.fMask := SIF_RANGE or SIF_PAGE or SIF_TRACKPOS; + GetScrollInfo(Handle, ScrollBar, SI); + {$IF DEFINED(LCLGTK2)} + {.$WARNING "scrollbar arrows still not working properly on GTK2 in some cases!"} + SI.nTrackPos := Delta; + {$IFEND} + I := PPos^; + case ScrollCode of + SB_TOP: I := SI.nMin; + SB_BOTTOM: I := SI.nMax; // will be trimmed below + SB_LINEUP: Dec(I, SI.nPage div Divisor); + SB_LINEDOWN: Inc(I, SI.nPage div Divisor); + SB_PAGEUP: Dec(I, SI.nPage); + SB_PAGEDOWN: Inc(I, SI.nPage); + SB_THUMBTRACK, SB_THUMBPOSITION: I := SI.nTrackPos; + else + Inc(I, Delta) + end; + if FScaleMode = smWholePage then + I := MinMax(I, 1, PExtent^) + else + I := MinMax(I, 0, PExtent^); + PPos^ := I; + SI.nPos := I; + SI.fMask := SIF_POS; + SetScrollInfo(Handle, ScrollBar, SI, True); + end; +end; + +procedure TKPrintPreview.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +begin + inherited; + if ssLeft in Shift then + begin + SafeSetFocus; + if (FScaleMode <> smWholePage) and PtInRect(GetPageRect, Point(X, Y)) then + begin + FlagSet(cPF_Dragging); + FX := X; + FY := Y; + SetMouseCursor(X, Y); + end; + end; +end; + +procedure TKPrintPreview.MouseMove(Shift: TShiftState; X, Y: Integer); +begin + inherited; + if Flag(cPF_Dragging) and MouseCapture then + begin + BeginScrollWindow; + if (X > FX) and (FScrollPos.X > 0) or (X < FX) and (FScrollPos.X < FScrollExtent.X) then + begin + ModifyScrollBar(SB_HORZ, -1, FX - X); + FX := X; + end; + if (Y > FY) and (FScrollPos.Y > 0) or (Y < FY) and (FScrollPos.Y < FScrollExtent.Y) then + begin + ModifyScrollBar(SB_VERT, -1, FY - Y); + FY := Y; + end; + EndScrollWindow; + end; +end; + +procedure TKPrintPreview.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +begin + inherited; + FlagClear(cPF_Dragging); + SetMouseCursor(X, Y); +end; + +procedure TKPrintPreview.NextPage; +begin + Page := Page + 1; +end; + +procedure TKPrintPreview.Notification(AComponent: TComponent; + Operation: TOperation); +begin + inherited; + if (Operation = opRemove) and (AComponent = FControl) then + begin + FControl := nil; + UpdatePreview; + end; +end; + +procedure TKPrintPreview.Paint; + + procedure DoPaint(IsBuffer: Boolean); + var + C: TColor; + R, RPaper, RPage: TRect; + RgnPaper: HRGN; + begin + Canvas.Brush.Style := bsSolid; + Canvas.Pen.Mode := pmCopy; + Canvas.Pen.Style := psSolid; + Canvas.Pen.Width := 1; + RPage := GetPageRect; + RPaper := RPage; + with RPaper do + begin + Inc(Right, cPreviewShadowSize); + Inc(Bottom, cPreviewShadowSize); + end; + if not IsBuffer then + RgnPaper := CreateRectRgnIndirect(RPaper) + else + RgnPaper := 0; + try + // paint background around paper, we don't want at least this to flicker + if IsBuffer or (ExtSelectClipRgn(Canvas.Handle, RgnPaper, RGN_DIFF) <> NULLREGION) then + begin + Canvas.Brush.Color := FColors.BkGnd; + Canvas.FillRect(ClientRect); + end; + if not IsBuffer then + SelectClipRgn(Canvas.Handle, RgnPaper); + finally + if not IsBuffer then + DeleteObject(rgnPaper); + end; + // paint paper outline + if Focused then + C := FColors.SelectedBorder + else + C := FColors.Border; + Canvas.Pen.Color := C; + Canvas.Brush.Color := FColors.Paper; + Canvas.Rectangle(RPage); + Canvas.Brush.Color := FColors.BkGnd; + R := Rect(RPage.Left, RPage.Bottom, RPage.Left + cPreviewShadowSize, RPage.Bottom + cPreviewShadowSize); + Canvas.FillRect(R); + R := Rect(RPage.Right, RPage.Top, RPage.Right + cPreviewShadowSize, RPage.Top + cPreviewShadowSize); + Canvas.FillRect(R); + Canvas.Brush.Color := C; + R := Rect(RPage.Left + cPreviewShadowSize, RPage.Bottom, RPaper.Right, RPaper.Bottom); + Canvas.FillRect(R); + R := Rect(RPage.Right, RPage.Top + cPreviewShadowSize, RPaper.Right, RPaper.Bottom); + Canvas.FillRect(R); + // paint page outline + InflateRect(RPage, -1, -1); + FControl.PageSetup.PaintPageToPreview(Self); + end; + +var + SaveIndex: Integer; + RClient: TRect; +{$IFDEF USE_WINAPI} + Org: TPoint; + MemBitmap, OldBitmap: HBITMAP; + DC: HDC; +{$ENDIF} +begin + RClient := ClientRect; + if Assigned(FControl) then + begin + SaveIndex := SaveDC(Canvas.Handle); + try + {$IFDEF USE_WINAPI} + if DoubleBuffered then + begin + // we must paint always the entire client because of canvas scaling + MemBitmap := CreateCompatibleBitmap(Canvas.Handle, RClient.Right - RClient.Left, RClient.Bottom - RClient.Top); + try + OldBitmap := SelectObject(Canvas.Handle, MemBitmap); + try + SetWindowOrgEx(Canvas.Handle, 0, 0, @Org); + SelectClipRect(Canvas.Handle, Rect(0, 0, RClient.Right - RClient.Left, RClient.Bottom - RClient.Top)); + DoPaint(True); + finally + SelectObject(Canvas.Handle, OldBitmap); + SetWindowOrgEx(Canvas.Handle, Org.X, Org.Y, nil); + end; + // copy MemBitmap to original canvas + DC := CreateCompatibleDC(Canvas.Handle); + try + OldBitmap := SelectObject(DC, MemBitmap); + try + CopyBitmap(Canvas.Handle, RClient, DC, 0, 0); + finally + SelectObject(DC, OldBitmap); + end; + finally + DeleteDC(DC); + end; + finally + DeleteObject(MemBitmap); + end; + end else + {$ENDIF} + DoPaint(False); + finally + RestoreDC(Canvas.Handle, SaveIndex); + end; + end else + begin + Canvas.Brush.Color := FColors.BkGnd; + Canvas.FillRect(RClient); + end; +end; + +procedure TKPrintPreview.Changed; +begin + if Assigned(FOnChanged) then + FOnChanged(Self); +end; + +procedure TKPrintPreview.PreviousPage; +begin + Page := Page - 1; +end; + +procedure TKPrintPreview.SafeSetFocus; +var + Form: TCustomForm; +begin + Form := GetParentForm(Self); + if (Form <> nil) and Form.Visible and Form.Enabled and Visible and Enabled then + Form.ActiveControl := Self; +end; + +procedure TKPrintPreview.SetColors(const Value: TKPreviewColors); +begin + FColors.Assign(Value); +end; + +procedure TKPrintPreview.SetControl(Value: TKCustomControl); +begin + if (Value <> FControl) and (Value <> Self) and not (Value is TKPrintPreview) then + begin + if Assigned(FControl) then + FControl.RemovePreview(Self); + FControl := Value; + if Assigned(FControl) then + FControl.AddPreview(Self); + UpdatePreview; + end; +end; + +procedure TKPrintPreview.SetPage(Value: Integer); +begin + Value := MinMax(Value, StartPage, EndPage); + if Value <> FPage then + begin + BeginScrollWindow; + if FScaleMode = smWholePage then + ModifyScrollBar(SB_VERT, -1, Value - FPage) + else + FPage := Value; + EndScrollWindow; + Changed; + end; +end; + +procedure TKPrintPreview.SetScale(Value: Integer); +begin + Value := MinMax(Value, cScaleMin, cScaleMax); + if Value <> FScale then + begin + FScale := Value; + UpdatePreview; + end; +end; + +procedure TKPrintPreview.SetScaleMode(Value: TKPreviewScaleMode); +begin + if Value <> FScaleMode then + begin + FScaleMode := Value; + UpdatePreview; + end; +end; + +function TKPrintPreview.SetMouseCursor(X, Y: Integer): Boolean; +var + ACursor: TCursor; +begin + if PtInRect(GetPageRect, Point(X, Y)) and (FScaleMode <> smWholePage) then + begin + if MouseCapture then + ACursor := crDragHandGrip + else + ACursor := crDragHandFree; + end else + ACursor := crDefault; +{$IFDEF FPC} + FCursor := ACursor; + SetTempCursor(ACursor); +{$ELSE} + Windows.SetCursor(Screen.Cursors[ACursor]); +{$ENDIF} + Result := True; +end; + +procedure TKPrintPreview.UpdatePreview; +begin + Page := FPage; + UpdateScrollRange; + Changed; +end; + +procedure TKPrintPreview.UpdateScrollRange; +var + I: Integer; + PageWidth100Percent, PageHeight100Percent: Integer; + SI: TScrollInfo; +begin + if HandleAllocated and not Flag(cPF_UpdateRange) then + begin + FlagSet(cPF_UpdateRange); + try + if Assigned(FControl) then + begin + // get isotropic page size in 300 dpi + PageWidth100Percent := MulDiv(FControl.PageSetup.PageWidth, 300, FControl.PageSetup.PrinterPixelsPerInchX); + PageHeight100Percent := MulDiv(FControl.PageSetup.PageHeight, 300, FControl.PageSetup.PrinterPixelsPerInchY); + case FScaleMode of + smScale: + begin + FPageSize.X := MulDiv(PageWidth100Percent, FScale, 100); + FPageSize.Y := MulDiv(PageHeight100Percent, FScale, 100); + end; + smPageWidth: + begin + FPageSize.X := Max(ClientWidth - 2 * cPreviewHorzBorder - cPreviewShadowSize, 40); + FPageSize.Y := MulDiv(FPageSize.X, PageHeight100Percent, PageWidth100Percent); + end; + smWholePage: + begin + FPageSize.X := Max(ClientWidth - 2 * cPreviewHorzBorder - cPreviewShadowSize, 40); + FPageSize.Y := Max(ClientHeight - 2 * cPreviewVertBorder - cPreviewShadowSize, 40); + I := MulDiv(FPageSize.Y, PageWidth100Percent, PageHeight100Percent); + if I < FPageSize.X then + FPageSize.X := I + else + FPageSize.Y := MulDiv(FPageSize.X, PageHeight100Percent, PageWidth100Percent); + end; + end; + FExtent.X := FPageSize.X + 2 * cPreviewHorzBorder + cPreviewShadowSize; + FExtent.Y := FPageSize.Y + 2 * cPreviewVertBorder + cPreviewShadowSize; + FPageOffset.X := cPreviewHorzBorder; + if (FExtent.X < ClientWidth) then + Inc(FPageOffset.X, (ClientWidth - FExtent.X) div 2); + FPageOffset.Y := cPreviewVertBorder; + if (FExtent.Y < ClientHeight) then + Inc(FPageOffset.Y, (ClientHeight - FExtent.Y) div 2); + // adjust horizontal scroll position + I := FScrollPos.X + ClientWidth - FExtent.X - 1; + if I > 0 then + Dec(FScrollPos.X, I); + FScrollPos.X := Max(FScrollPos.X, 0); + // adjust vertical scroll position + I := FScrollPos.Y + ClientHeight - FExtent.Y - 1; + if I > 0 then + Dec(FScrollPos.Y, I); + FScrollPos.Y := Max(FScrollPos.Y, 0); + // update scroll range + FScrollExtent.X := 0; + FScrollExtent.Y := 0; + FillChar(SI, SizeOf(TScrollInfo), 0); + SI.cbSize := SizeOf(TScrollInfo); + SI.fMask := SIF_RANGE or SIF_PAGE or SIF_POS or SIF_DISABLENOSCROLL {$IFDEF UNIX}or SIF_UPDATEPOLICY{$ENDIF}; + SI.nMin := 0; + {$IFDEF UNIX} + SI.ntrackPos := SB_POLICY_CONTINUOUS; + {$ENDIF} + case FScaleMode of + smScale: + begin + ShowScrollbar(Handle, SB_HORZ, True); + ShowScrollbar(Handle, SB_VERT, True); + SI.nMax := FExtent.X{$IFDEF FPC}+ 1{$ENDIF}; + SI.nPage := ClientWidth; + SI.nPos := FScrollPos.X; + FScrollExtent.X := SI.nMax - Integer(SI.nPage); + SetScrollInfo(Handle, SB_HORZ, SI, True); + SI.nMax := FExtent.Y{$IFDEF FPC}+ 1{$ENDIF}; + SI.nPage := ClientHeight; + SI.nPos := FScrollPos.Y; + FScrollExtent.Y := SI.nMax - Integer(SI.nPage); + SetScrollInfo(Handle, SB_VERT, SI, True); + end; + smPageWidth: + begin + ShowScrollbar(Handle, SB_HORZ, False); + ShowScrollbar(Handle, SB_VERT, True); + SI.nMax := FExtent.Y{$IFDEF FPC}+ 1{$ENDIF}; + SI.nPage := ClientHeight; + SI.nPos := FScrollPos.Y; + FScrollExtent.Y := SI.nMax - Integer(SI.nPage); + SetScrollInfo(Handle, SB_VERT, SI, True); + end; + smWholePage: + begin + // another mode for vertical scrollbar - page selection + ShowScrollbar(Handle, SB_HORZ, False); + ShowScrollbar(Handle, SB_VERT, True); + SI.nMin := StartPage; + SI.nMax := EndPage{$IFDEF FPC}+ 1{$ENDIF}; + SI.nPage := 1; + SI.nPos := FPage; + SetScrollInfo(Handle, SB_VERT, SI, True); + end; + end; + end else + begin + ShowScrollbar(Handle, SB_HORZ, False); + ShowScrollbar(Handle, SB_VERT, False); + end; + Invalidate; + finally + FlagClear(cPF_UpdateRange); + end; + end; +end; + +procedure TKPrintPreview.UpdateSize; +begin + inherited; + UpdatePreview; +end; + +procedure TKPrintPreview.WMEraseBkgnd(var Msg: TLMessage); +begin + Msg.Result := 1; +end; + +procedure TKPrintPreview.WMGetDlgCode(var Msg: TLMNoParams); +begin + Msg.Result := DLGC_WANTARROWS; +end; + +procedure TKPrintPreview.WMHScroll(var Msg: TLMHScroll); +begin + SafeSetFocus; + BeginScrollWindow; + ModifyScrollBar(SB_HORZ, Msg.ScrollCode, Msg.Pos); + EndScrollWindow; +end; + +procedure TKPrintPreview.WMKillFocus(var Msg: TLMKillFocus); +begin + inherited; + Invalidate; +end; + +procedure TKPrintPreview.WMSetFocus(var Msg: TLMSetFocus); +begin + inherited; + Invalidate; +end; + +procedure TKPrintPreview.WMVScroll(var Msg: TLMVScroll); +begin + SafeSetFocus; + BeginScrollWindow; + ModifyScrollBar(SB_VERT, Msg.ScrollCode, Msg.Pos); + EndScrollWindow; +end; + +{$IFDEF FPC} +initialization + {$i kcontrols.lrs} +{$ELSE} + {$R kcontrols.res} +{$ENDIF} +end. diff --git a/components/kcontrols/source/kcontrols.res b/components/kcontrols/source/kcontrols.res new file mode 100755 index 0000000000000000000000000000000000000000..8e075377833d1aca6e6663895f6c1cd0505c8d96 GIT binary patch literal 912 zcmcJMu}*_f6o!AO4U2{jF2@k{M`3VqWHKF0 zkKegagE67e#6!Nrg>!(*`6MX=vkI2qVkcVEBYL9<#*EDWT|?O`XUr2RV%5 z0g9SwmpZ+#soDI#{oPd8*~J-{t?Go;xrVyZhfgQ9dkd$ez!9X-$K$}kqx%d_-=xhO{U(+Uw%JhP i!YRPr + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/kcontrols/source/kdbgrids.pas b/components/kcontrols/source/kdbgrids.pas new file mode 100755 index 000000000..65603df73 --- /dev/null +++ b/components/kcontrols/source/kdbgrids.pas @@ -0,0 +1,1495 @@ +{ @abstract(This unit contains the TKDBGrid component and all supporting classes) + @author(Tomas Krysl (tk@tkweb.eu)) + @created(20 Sep 2009) + @lastmod(20 Jun 2010) + + Copyright © 2009 Tomas Krysl (tk@@tkweb.eu)

+ + This unit provides a data aware control for TKGrid. + Note: I am still a newbie to Delphi/Lazarus database solutions. If anything + is totally wrong here please feel free to send a patch or hint to me. + + License:
+ This code is distributed as a freeware. You are free to use it as part + of your application for any purpose including freeware, commercial and + shareware applications. The origin of this source code must not be + misrepresented; you must not claim your authorship. You may modify this code + solely for your own purpose. However, you may distribute only the original + package. The Author accepts no liability for any damage that may result + from using this code. } + +unit KDBGrids; + +{$include kcontrols.inc} +{$WEAKPACKAGEUNIT ON} + +interface + +uses +{$IFDEF FPC} + LCLType, LCLIntf, LCLProc, LResources, +{$ELSE} + Windows, Messages, +{$ENDIF} + SysUtils, Classes, Graphics, Controls, Forms, ExtCtrls, DB, DBCtrls, + KFunctions, KGraphics, KGrids; + +resourcestring + { @exclude } + SKDBGridIndex = 'Index'; + +type + { Declares possible values for the @link(TKCustomDBGrid.DBOptions) property. } + TKDBGridOption = ( + { Automatically moves current record to edited or selected row. } + dboAutoMoveRecord, + { Forces the cells with boolean fields to be automatically adjusted to checkbox frame size. } + dboAutoSizeBooleanCells, + { Forces the cells with image fields to be automatically adjusted to image size. } + dboAutoSizeImageCells, + { Forces the column names to be assigned to fixed cells in the first fixed row. } + dboColNamesToHeader, + { Does not clear fixed cell texts if table is closed. } + dboDontClearFixedCells, + { For all BLOB/image columns, images will be displayed in original size in the cell hint window. } + dboImageHint, + { Images loaded from database can be modified by user and thus will be + saved into database if this option is included. } + dboImagesWritable, + { Forces the row indexes to be assigned to fixed cells in the first fixed column. } + dboIndexFixedCol, + { Indicates the active record row. } + dboIndicateActiveRecord + ); + + { Set type for @link(TKDBGridOption) enumeration. } + TKDBGridOptions = set of TKDBGridOption; + +const + { Default value for the @link(TKCustomDBGrid.DBOptions) property. } + cDBOptionsDef = [dboAutoMoveRecord, dboAutoSizeBooleanCells, + dboColNamesToHeader, dboIndexFixedCol, dboIndicateActiveRecord]; + + { Default value for the @link(TKDBGridColors.ActiveRecord) property. } + cActiveRecordDef = clCream; + + { Used by default to distinguish image field type. } + cDefaultImageSet = [ftBlob, ftGraphic]; + + { Used by default to distinguish string field type. } + cDefaultStringSet = [ftString, ftSmallInt, ftInteger, ftWord, ftBoolean, ftFloat, + ftCurrency, ftBCD, ftDate, ftTime, ftDateTime, ftAutoInc, ftMemo, ftFmtMemo, + ftFixedChar, ftWideString, ftLargeInt, ftGuid, ftTimeStamp, ftFmtBCD + {$IF DEFINED(FPC) OR DEFINED(COMPILER10_UP)} + , ftWideMemo + {$IFEND} + ]; + + { Index for the @link(TKDBGridColors.ActiveRecord) property. } + ciActiveRecord = TKGridColorIndex(ciGridColorsMax + 1); + { Maximum color array index } + ciDBGridColorsMax = ciActiveRecord; + + { This internal flag is set if grid is being updated. } + cGF_DBDataUpdating = $00010000; + { This internal flag is set if data record is being changed. } + cGF_DBInternalChanging = $00020000; + +type + TKCustomDBGrid = class; + + { @abstract(Data link override for TKCustomDBGrid) + This class overrides TDataLink to extend behavior for TKCustomDBGrid. } + TKDBGridDataLink = class(TDataLink) + private + FGrid: TKCustomDBGrid; + FModified: Boolean; + procedure SetModified(const Value: Boolean); + protected + { Called if data set has been opened or closed. } + procedure ActiveChanged; override; + { Called if data in the data set has been changed. } + procedure DataSetChanged; override; + { Called if current record has been moved. } + procedure DataSetScrolled(Distance: Integer); override; + { Called if data set layout has been modified. } + procedure LayoutChanged; override; + { Called if current record has been modified. } + procedure RecordChanged(Field: TField); override; + { Called if unsaved data is about to be saved into database. } + procedure UpdateData; override; + public + { Creates the instance. } + constructor Create(AGrid: TKCustomDBGrid); + { Specifies the TKCustomDBGrid instance assigned to this TKDBGridDataLink instance. } + property Grid: TKCustomDBGrid read FGrid; + { Determines if the current record has been modified. } + property Modified: Boolean read FModified write SetModified; + end; + +{$IFDEF TKDBGRIDCELL_IS_TKGRIDATTRTEXTCELL} + { @exclude } + TKDBGridCellAncestor = TKGridAttrTextCell; +{$ELSE} + { @exclude } + TKDBGridCellAncestor = TKGridTextCell; +{$ENDIF} + + { @abstract(Base cell class for TKDBGrid) + This is the base cell class. It has always a Text property. Descendants can + add other specific data, e.g. BLOB pointers etc. } + TKDBGridCell = class(TKDBGridCellAncestor) + private + FGraphic: TGraphic; + protected + { Calls @link(TKCustomDBGrid.BeforeCellUpdate). } + procedure BeforeUpdate; override; + { Loads appropriate image. } + function CreateImageByType(const Header: TKImageHeaderString): TGraphic; virtual; + { Assigns cell properties to field data. } + procedure FieldFromCell(AField: TField); virtual; + { Assigns field data to cell properties. } + procedure FieldToCell(AField: TField); virtual; + { Assigns AField buffer to Graphic property. } + procedure ImageFromField(AField: TField); + { Assigns Graphic property to AField buffer. } + procedure ImageToField(AField: TField); + { Initializes the cell data. } + procedure Initialize; override; + { Assigns AField buffer to Text property. } + procedure TextFromField(AField: TField); + { Assigns Text property to AField buffer. } + procedure TextToField(AField: TField); + public + { Creates the instance. } + constructor Create(AGrid: TKCustomGrid); override; + { Applies TKDBGridCell properties to the cell painter. } + procedure ApplyDrawProperties; override; + { Returns a pointer to the image read from database. } + property Graphic: TGraphic read FGraphic; + end; + + { @abstract(Column class for TKCustomDBGrid) + This column class implements some extra properties for TKCustomDBGrid. } + TKDBGridCol = class(TKGridCol) + private + FCurrencyFormat: TKCurrencyFormat; + FDataType: TFieldType; + FName: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; + public + { Creates the instance. Do not create custom instances. All necessary + TKDBGridCol instances are created automatically by TKCustomDBGrid. } + constructor Create(AGrid: TKCustomGrid); override; + { Specifies the currency formatting settings if the column has currency data type. } + property CurrencyFormat: TKCurrencyFormat read FCurrencyFormat write FCurrencyFormat; + { Returns the field data type. It is assigned automatically + by the TKDGGrid's data source. } + property DataType: TFieldType read FDataType; + { Specifies the database column name. It is assigned automatically + by the TKDGGrid's data source. } + property Name: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF} read FName; + end; + + { @abstract(Metaclass for @link(TKDBGridCol)). } + TKDBGridColClass = class of TKDBGridCol; + + { @abstract(Cell painter class used by TKCustomDBGrid class) + Overrides some TKGridCellPainter methods for usage with TKCustomDBGrid. } + TKDBGridCellPainter = class(TKGridCellPainter) + public + { Low level method. Prepares default painting attributes. Applies + attributes specific for TKDBGrid. } + procedure DefaultAttributes; override; + end; + + { @abstract(Container for all colors used by TKCustomDBGrid class) + Adds some extra colors used by TKCustomDBGrid. } + TKDBGridColors = class(TKGridColors) + private + function GetColor(Index: TKGridColorIndex): TColor; + procedure SetColor(Index: TKGridColorIndex; Value: TColor); + protected + { Initializes the color array. } + procedure Initialize; override; + published + { Specifies the color used to indicate active record. } + property ActiveRecord: TColor index ciActiveRecord read GetColor write SetColor default cActiveRecordDef; + end; + + { @abstract(KGrid data aware base component) This is the class that you use as + the ancestor for your TKCustomDBGrid overrides. } + TKCustomDBGrid = class(TKCustomGrid) + private + FActiveRecord: Integer; + FDBOptions: TKDBGridOptions; + function GetDataSource: TDataSource; + procedure SetDataSource(Value: TDataSource); + procedure SetDBOptions(const Value: TKDBGridOptions); + protected + { This field represents the internal data link. } + FDataLink: TKDBGridDataLink; + { Does nothing. Row moving not supported. } + function BeginRowDrag(var Origin: Integer; const MousePt: TPoint): Boolean; override; + { Fills the grid with data from database and/or updates the grid. } + procedure DataChanged; dynamic; + { Called if current record has been moved. } + procedure DataSetScrolled; dynamic; + { Extends TKCustomGrid behavior. Sets the data set into edited state and + informs the data link about cell change. } + procedure Changed; override; + { Extends TKCustomGrid behavior. Updates the grid if column has been moved. } + procedure ColMoved(FromIndex, ToIndex: Integer); override; + { Extends TKCustomGrid behavior. Calls the event if data set is active etc. } + function CustomSortRows(ByCol: Integer; var SortMode: TKGridSortMode): Boolean; override; + { Extends TKCustomGrid behavior. Does not allow to edit if data set is writable + or closed etc. } + function EditorCreate(ACol, ARow: Integer): TWinControl; override; + { Moves to another record if initiated by the grid. } + procedure InternalSetActiveRecord(Value: Integer); dynamic; + { Used internally to set column count. } + procedure InternalSetColCount(Value: Integer); override; + { Used internally to set fixed column count. } + procedure InternalSetFixedCols(Value: Integer); override; + { Used internally to set fixed row count. } + procedure InternalSetFixedRows(Value: Integer); override; + { Used internally to set row count. } + procedure InternalSetRowCount(Value: Integer); override; + { Allows to decide whether the goVirtualGrid option can be modified. + Returns always False as no virtual grid possible in TKDBGrid. } + function InternalUpdateVirtualGrid: Boolean; override; + { Called if current record has been modified. } + procedure RecordChanged; dynamic; + { Extends TKCustomGrid behavior. Forces the previous modified record to be + written into database. } + function SelectCell(ACol, ARow: Integer): Boolean; override; + { Extends TKCustomGrid behavior. Updates the grid if top row or left column has + been changed. } + procedure TopLeftChanged; override; + { Called if unsaved data is about to be saved into database. } + procedure UpdateData; dynamic; + { Extends TKCustomGrid Behavior. Updates the grid if control size has + been changed. } + procedure UpdateSize; override; + public + { Creates the instance. Assigns default values to properties, allocates + default column, row and cell data, constucts a data link. } + constructor Create(AOwner: TComponent); override; + { Destroys the instance along with all allocated column, row and cell data, + destroys the data link. } + destructor Destroy; override; + { Notifies the grid that a cell has been modified. } + procedure BeforeCellUpdate(ACol, ARow: Integer); dynamic; + { Does nothing. Clearing entire column is not supported. } + procedure ClearCol(ACol: Integer); override; + { Does nothing. Clearing entire grid is not supported. } + procedure ClearGrid; override; + { Does nothing. Clearing entire row is not supported. } + procedure ClearRow(ARow: Integer); override; + { Writes any modified data in the current record into database. } + procedure Commit; dynamic; + { Provides default behavior for the @link(OnEditorCreate) event. } + procedure DefaultEditorCreate(ACol, ARow: Integer; + var AEditor: TWinControl); override; + { Provides default behavior for the @link(OnEditorDataFromGrid) event. } + procedure DefaultEditorDataFromGrid(AEditor: TWinControl; + ACol, ARow: Integer; var AssignText: Boolean); override; + { Provides default behavior for the @link(OnEditorDataToGrid) event. } + procedure DefaultEditorDataToGrid(AEditor: TWinControl; + ACol, ARow: Integer; var AssignText: Boolean); override; + { Provides default behavior for the @link(OnEditorResize) event. } + procedure DefaultEditorResize(AEditor: TWinControl; + ACol, ARow: Integer; var ARect: TRect); override; + { Provides default behavior for the @link(OnEditorSelect) event. } + procedure DefaultEditorSelect(AEditor: TWinControl; + ACol, ARow: Integer; SelectAll, CaretToLeft, SelectedByMouse: Boolean); override; + { Provides default cell hint behavior. } + procedure DefaultMouseCellHint(ACol, ARow: Integer; AShow: Boolean); override; + { Does nothing. Deleting columns not supported. } + procedure DeleteCols(At, Count: Integer); override; + { Forces the data set to delete record at location At. } + procedure DeleteRow(At: Integer); override; + { Does nothing. Deleting more rows not supported. } + procedure DeleteRows(At, Count: Integer); override; + { Does nothing. Inserting columns not supported. } + procedure InsertCols(At, Count: Integer); override; + { Forces the data set to insert new record at location At. } + procedure InsertRow(At: Integer); override; + { Does nothing. Inserting more rows not supported. } + procedure InsertRows(At, Count: Integer); override; + { Does nothing. Inserting sorted columns not supported. } + function InsertSortedCol(out ByRow, ACol: Integer): Boolean; override; + { Does nothing. Inserting sorted rows not supported. } + function InsertSortedRow(out ByCol, ARow: Integer): Boolean; override; + { Does nothing. Row moving not supported. } + procedure MoveRow(FromIndex, ToIndex: Integer); override; + { Specifies the data source. } + property DataSource: TDataSource read GetDataSource write SetDataSource; + { Specifies various display and behavioral properties of TKDGGrid. } + property DBOptions: TKDBGridOptions read FDBOptions write SetDBOptions default cDBOptionsDef; + end; + + { For backward compatibility. } + TKDBCustomGrid = TKCustomDBGrid; + + { @abstract(KDBGrid design-time component) This is the class you use both + on run-time and design-time. } + TKDBGrid = class(TKCustomDBGrid) + published + { Inherited property - see Delphi help. } + property Align; + { Inherited property - see Delphi help. } + property Anchors; + { See TKCustomGrid.@link(TKCustomControl.BorderStyle) for details. } + property BorderStyle; + { Inherited property - see Delphi help. } + property BorderWidth; + { See TKCustomDBGrid.@link(TKCustomDBGrid.DBOptions) for details. } + property DBOptions; + { See TKCustomGrid.@link(TKCustomGrid.ColCount) for details. } + property ColCount; + { See TKCustomGrid.@link(TKCustomGrid.Color) for details. } + property Color; + { See TKCustomGrid.@link(TKCustomGrid.Colors) for details. } + property Colors; + { Inherited property - see Delphi help. } + property Constraints; + {$IFDEF FPC} + { See TKCustomGrid.@link(TKCustomGrid.Flat) for details. } + property Flat; + {$ELSE} + { Inherited property - see Delphi help. } + property Ctl3D; + {$ENDIF} + { See TKCustomDBGrid.@link(TKCustomDBGrid.DataSource) for details. } + property DataSource; + { See TKCustomGrid.@link(TKCustomGrid.DefaultColWidth) for details. } + property DefaultColWidth; + { See TKCustomGrid.@link(TKCustomGrid.DefaultDrawing) for details. } + property DefaultDrawing; + { See TKCustomGrid.@link(TKCustomGrid.DefaultRowHeight) for details. } + property DefaultRowHeight; + { See TKCustomGrid.@link(TKCustomGrid.DisabledDrawStyle) for details. } + property DisabledDrawStyle; + { Inherited property - see Delphi help. } + property DragCursor; + { Inherited property - see Delphi help. } + property DragKind; + { Inherited property - see Delphi help. } + property DragMode; + { See TKCustomGrid.@link(TKCustomGrid.DragStyle) for details. } + property DragStyle; + { Inherited property - see Delphi help. } + property Enabled; + { See TKCustomGrid.@link(TKCustomGrid.FixedCols) for details. } + property FixedCols; + { See TKCustomGrid.@link(TKCustomGrid.FixedRows) for details. } + property FixedRows; + { Inherited property - see Delphi help. } + property Font; + { See TKCustomGrid.@link(TKCustomGrid.GridLineWidth) for details. } + property GridLineWidth; + { See TKCustomGrid.@link(TKCustomGrid.MinColWidth) for details. } + property MinColWidth; + { See TKCustomGrid.@link(TKCustomGrid.MinRowHeight) for details. } + property MinRowHeight; + { See TKCustomGrid.@link(TKCustomGrid.MouseCellHintTime) for details. } + property MouseCellHintTime; + { See TKCustomGrid.@link(TKCustomGrid.MoveDirection) for details. } + property MoveDirection; + { See TKCustomGrid.@link(TKCustomGrid.Options) for details. } + property Options; + { Inherited property - see Delphi help. } + property ParentColor; + { Inherited property - see Delphi help. } + property ParentFont; + { Inherited property - see Delphi help. } + property ParentShowHint; + { Inherited property - see Delphi help. } + property PopupMenu; + { See TKCustomGrid.@link(TKCustomGrid.RangeSelectStyle) for details. } + property RangeSelectStyle; + { See TKCustomGrid.@link(TKCustomGrid.RowCount) for details. } + property RowCount; + { See TKCustomGrid.@link(TKCustomGrid.ScrollBars) for details. } + property ScrollBars; + { See TKCustomGrid.@link(TKCustomGrid.ScrollModeHorz) for details. } + property ScrollModeHorz; + { See TKCustomGrid.@link(TKCustomGrid.ScrollModeVert) for details. } + property ScrollModeVert; + { See TKCustomGrid.@link(TKCustomGrid.ScrollSpeed) for details. } + property ScrollSpeed; + { Inherited property - see Delphi help. } + property ShowHint; + { See TKCustomGrid.@link(TKCustomGrid.SizingStyle) for details. } + property SizingStyle; + { See TKCustomGrid.@link(TKCustomGrid.SortStyle) for details. } + property SortStyle; + { Inherited property - see Delphi help. } + property TabOrder; + { Inherited property - see Delphi help. } + property TabStop default True; + { Inherited property - see Delphi help. } + property Visible; + { See TKCustomGrid.@link(TKCustomGrid.OnBeginColDrag) for details. } + property OnBeginColDrag; + { See TKCustomGrid.@link(TKCustomGrid.OnBeginColSizing) for details. } + property OnBeginColSizing; + { See TKCustomGrid.@link(TKCustomGrid.OnBeginRowSizing) for details. } + property OnBeginRowSizing; + { See TKCustomGrid.@link(TKCustomGrid.OnCellSpan) for details. } + property OnCellSpan; + { See TKCustomGrid.@link(TKCustomGrid.OnChanged) for details. } + property OnChanged; + { See TKCustomGrid.@link(TKCustomGrid.OnCheckColDrag) for details. } + property OnCheckColDrag; + { Inherited property - see Delphi help. } + property OnClick; + { See TKCustomGrid.@link(TKCustomGrid.OnColumnMoved) for details. } + property OnColumnMoved; + { See TKCustomGrid.@link(TKCustomGrid.OnColWidthsChanged) for details. } + property OnColWidthsChanged; + { Inherited property - see Delphi help. } + property OnContextPopup; + { See TKCustomGrid.@link(TKCustomGrid.OnCustomSortCols) for details. } + property OnCustomSortCols; + { See TKCustomGrid.@link(TKCustomGrid.OnCustomSortRows) for details. } + property OnCustomSortRows; + { Inherited property - see Delphi help. } + property OnDblClick; + { Inherited property - see Delphi help. } + property OnDockDrop; + { Inherited property - see Delphi help. } + property OnDockOver; + { Inherited property - see Delphi help. } + property OnDragDrop; + { Inherited property - see Delphi help. } + property OnDragOver; + { See TKCustomGrid.@link(TKCustomGrid.OnDrawCell) for details. } + property OnDrawCell; + { See TKCustomGrid.@link(TKCustomGrid.OnEditorCreate) for details. } + property OnEditorCreate; + { See TKCustomGrid.@link(TKCustomGrid.OnEditorDataFromGrid) for details. } + property OnEditorDataFromGrid; + { See TKCustomGrid.@link(TKCustomGrid.OnEditorDataToGrid) for details. } + property OnEditorDataToGrid; + { See TKCustomGrid.@link(TKCustomGrid.OnEditorDestroy) for details. } + property OnEditorDestroy; + { See TKCustomGrid.@link(TKCustomGrid.OnEditorKeyPreview) for details. } + property OnEditorKeyPreview; + { See TKCustomGrid.@link(TKCustomGrid.OnEditorResize) for details. } + property OnEditorResize; + { See TKCustomGrid.@link(TKCustomGrid.OnEditorSelect) for details. } + property OnEditorSelect; + { See TKCustomGrid.@link(TKCustomGrid.OnEndColDrag) for details. } + property OnEndColDrag; + { See TKCustomGrid.@link(TKCustomGrid.OnEndColSizing) for details. } + property OnEndColSizing; + { Inherited property - see Delphi help. } + property OnEndDock; + { Inherited property - see Delphi help. } + property OnEndDrag; + { See TKCustomGrid.@link(TKCustomGrid.OnEndRowSizing) for details. } + property OnEndRowSizing; + { Inherited property - see Delphi help. } + property OnEnter; + { Inherited property - see Delphi help. } + property OnExit; + { See TKCustomGrid.@link(TKCustomGrid.OnExchangeCols) for details. } + property OnExchangeCols; + { See TKCustomGrid.@link(TKCustomGrid.OnExchangeRows) for details. } + property OnExchangeRows; + { Inherited property - see Delphi help. } + property OnGetSiteInfo; + { Inherited property - see Delphi help. } + property OnKeyDown; + { Inherited property - see Delphi help. } + property OnKeyPress; + { Inherited property - see Delphi help. } + property OnKeyUp; + { See TKCustomGrid.@link(TKCustomGrid.OnMouseCellHint) for details. } + property OnMouseCellHint; + { See TKCustomGrid.@link(TKCustomGrid.OnMouseClickCell) for details. } + property OnMouseClickCell; + { Inherited property - see Delphi help. } + property OnMouseDown; + { See TKCustomGrid.@link(TKCustomGrid.OnMouseEnterCell) for details. } + property OnMouseEnterCell; + { See TKCustomGrid.@link(TKCustomGrid.OnMouseLeaveCell) for details. } + property OnMouseLeaveCell; + { Inherited property - see Delphi help. } + property OnMouseMove; + { Inherited property - see Delphi help. } + property OnMouseUp; + { Inherited property - see Delphi help. } + property OnMouseWheel; + { Inherited property - see Delphi help. } + property OnMouseWheelDown; + { Inherited property - see Delphi help. } + property OnMouseWheelUp; + { Inherited property - see Delphi help. } + property OnResize; + { See TKCustomGrid.@link(TKCustomGrid.OnRowHeightsChanged) for details. } + property OnRowHeightsChanged; + { See TKCustomGrid.@link(TKCustomGrid.OnSelectCell) for details. } + property OnSelectCell; + { See TKCustomGrid.@link(TKCustomGrid.OnSelectionExpand) for details. } + property OnSelectionExpand; + { See TKCustomGrid.@link(TKCustomGrid.OnSizeChanged) for details. } + property OnSizeChanged; + { Inherited property - see Delphi help. } + property OnStartDock; + { Inherited property - see Delphi help. } + property OnStartDrag; + { See TKCustomGrid.@link(TKCustomGrid.OnTopLeftChanged) for details. } + property OnTopLeftChanged; + { Inherited property - see Delphi help. } + property OnUnDock; + end; + +implementation + +uses + Math, Types, ComCtrls, StdCtrls +{$IFDEF FPC} + , EditBtn +{$ENDIF} + ; + +{ TKDBGridDataLink } + +constructor TKDBGridDataLink.Create(AGrid: TKCustomDBGrid); +begin + inherited Create; + FGrid := AGrid; + FModified := False; + VisualControl := True; +end; + +procedure TKDBGridDataLink.ActiveChanged; +begin + inherited; + if Assigned(FGrid) then + FGrid.DataChanged; + FModified := False; +end; + +procedure TKDBGridDataLink.DataSetChanged; +begin + inherited; + if Assigned(FGrid) then + FGrid.DataChanged; + FModified := False; +end; + +procedure TKDBGridDataLink.DataSetScrolled(Distance: Integer); +begin + inherited; + if Assigned(FGrid) then + FGrid.DataSetScrolled; +end; + +procedure TKDBGridDataLink.LayoutChanged; +begin + inherited; + if Assigned(FGrid) then + FGrid.DataChanged; + FModified := False; +end; + +procedure TKDBGridDataLink.RecordChanged; +begin + inherited; + if Assigned(FGrid) and not FGrid.Flag(cGF_EditorUpdating or cGF_DBDataUpdating) then + begin + FGrid.RecordChanged; + FModified := False; + end; +end; + +procedure TKDBGridDataLink.SetModified(const Value: Boolean); +begin + FModified := FModified or Value; +end; + +procedure TKDBGridDataLink.UpdateData; +begin + if FModified and Assigned(FGrid) then + FGrid.UpdateData; + FModified := False; +end; + +{ TKGridDBCell } + +constructor TKDBGridCell.Create(AGrid: TKCustomGrid); +begin + FGraphic := nil; + inherited; +end; + +procedure TKDBGridCell.ApplyDrawProperties; +var + ACol: TKDBGridCol; +begin + inherited; + Grid.CellPainter.Graphic := FGraphic; + if not (gdFixed in Grid.CellPainter.State) and (Grid.Cols[Grid.CellPainter.Col] is TKDBGridCol) then + begin + ACol := TKDBGridCol(Grid.Cols[Grid.CellPainter.Col]); + case ACol.DataType of + ftBoolean: + Grid.CellPainter.Text := ''; + ftCurrency, ftBcd: + Grid.CellPainter.Text := FormatCurrency(StrToCurrDef(Grid.CellPainter.Text, 0), ACol.CurrencyFormat); + end; + end; +end; + +procedure TKDBGridCell.BeforeUpdate; +var + ACol, ARow: Integer; +begin + inherited; + if (Grid is TKDBGrid) and not Grid.Flag(cGF_EditorUpdating or cGF_DBDataUpdating) + and FindCell(ACol, ARow) then + TKDBGrid(Grid).BeforeCellUpdate(ACol, ARow); +end; + +function TKDBGridCell.CreateImageByType(const Header: TKImageHeaderString): TGraphic; +begin + Result := ImageByType(Header); +end; + +procedure TKDBGridCell.FieldFromCell(AField: TField); +begin + if AField <> nil then + begin + if AField.DataType in cDefaultStringSet then + TextToField(AField) + else if (AField.DataType in cDefaultImageSet) and + (dboImagesWritable in TKCustomDBGrid(Grid).DBOptions) then + ImageToField(AField); + // else - override TKDBGridCell + end; +end; + +procedure TKDBGridCell.FieldToCell(AField: TField); +begin + if AField <> nil then + begin + if AField.DataType in cDefaultStringSet then + begin + FreeAndNil(FGraphic); + TextFromField(AField); + end + else if AField.DataType in cDefaultImageSet then + begin + Text := ''; + ImageFromField(AField); + end; + // else - override TKDBGridCell + end; +end; + +procedure TKDBGridCell.ImageFromField(AField: TField); +var + MS: TMemoryStream; + S: AnsiString; +begin + if AField is TBlobField then + begin + FreeAndNil(FGraphic); + MS := TMemoryStream.Create; + try + TBlobField(AField).SaveToStream(MS); + if MS.Size > SizeOf(TKImageHeaderString) then + begin + MS.Seek(0, soFromBeginning); + SetLength(S, SizeOf(TKImageHeaderString)); + MS.Read(S[1], SizeOf(TKImageHeaderString)); + FGraphic := CreateImageByType(S); + if Assigned(FGraphic) then + begin + MS.Seek(0, soFromBeginning); + FGraphic.LoadFromStream(MS); + end; + end; + finally + MS.Free; + end; + end; +end; + +procedure TKDBGridCell.ImageToField(AField: TField); +var + MS: TMemoryStream; +begin + if (AField is TBlobField) and Assigned(FGraphic) then + begin + MS := TMemoryStream.Create; + try + FGraphic.SaveToStream(MS); + MS.Seek(0, soFromBeginning); + TBlobField(AField).LoadFromStream(MS); + finally + MS.Free; + end; + end; +end; + +procedure TKDBGridCell.Initialize; +begin + inherited; + FreeAndNil(FGraphic); +end; + +procedure TKDBGridCell.TextFromField(AField: TField); +begin +{$IFDEF STRING_IS_UNICODE} + Text := AField.AsString +{$ELSE} + {$IFDEF COMPILER10_UP} + Text := AField.AsWideString + {$ELSE} + Text := AField.AsString + {$ENDIF} +{$ENDIF} +end; + +procedure TKDBGridCell.TextToField(AField: TField); +begin + if not AField.ReadOnly then + try + {$IFDEF STRING_IS_UNICODE} + AField.AsString := Text + {$ELSE} + {$IFDEF COMPILER10_UP} + AField.AsWideString := Text + {$ELSE} + AField.AsString := Text + {$ENDIF} + {$ENDIF} + except + end +end; + +{ TKDBGridCol } + +constructor TKDBGridCol.Create(AGrid: TKCustomGrid); +begin + inherited; + FCurrencyFormat.CurrencyFormat := SysUtils.CurrencyFormat; + FCurrencyFormat.CurrencyDecimals := SysUtils.CurrencyDecimals; + FCurrencyFormat.CurrencyString := SysUtils.CurrencyString; + FCurrencyFormat.DecimalSep := SysUtils.DecimalSeparator; + FCurrencyFormat.ThousandSep := SysUtils.ThousandSeparator; + FCurrencyFormat.UseThousandSep := True; + FDataType := ftUnknown; + FName := ''; +end; + +{ TKDBGridCellPainter } + +procedure TKDBGridCellPainter.DefaultAttributes; +begin + inherited; + if Assigned(TKCustomDBGrid(Grid).FDataLink) then + begin + if (dboIndicateActiveRecord in TKCustomDBGrid(Grid).DBOptions) and + Assigned(TKCustomDBGrid(Grid).FDataLink.DataSet) and + (TKCustomDBGrid(Grid).FDataLink.ActiveRecord = Row - Grid.FixedRows) and + (State * [gdSelected, gdFocused] = []) then + Canvas.Brush.Color := TKDBGridColors(TKCustomDBGrid(Grid).Colors).ActiveRecord; + if (dboIndexFixedCol in TKCustomDBGrid(Grid).DBOptions) and (Col = 0) and (Grid.FixedCols > 0) then + HAlign := halRight; + if not (gdFixed in State) and (Grid.Cols[Col] is TKDBGridCol) then + case TKDBGridCol(Grid.Cols[Col]).DataType of + ftMemo + {$IF DEFINED(FPC) OR DEFINED(COMPILER10_UP)} + , ftWideMemo + {$IFEND} + : + Attributes := Attributes + [taLineBreak]; + ftCurrency, ftBCD, ftFmtBCD: + HAlign := halRight; + ftBoolean: + begin + CheckBox := True; + CheckBoxChecked := LowerCase(Grid.Cells[Col, Row]) = 'true'; + end; + end; + end; +end; + +{ TKDBGridColors } + +function TKDBGridColors.GetColor(Index: TKGridColorIndex): TColor; +begin + Result := InternalGetColor(Index); +end; + +procedure TKDBGridColors.Initialize; +begin + inherited; + SetLength(FColors, ciDBGridColorsMax + 1); + SetLength(FBrightColors, ciDBGridColorsMax + 1); + FColors[ciActiveRecord] := cActiveRecordDef; +end; + +procedure TKDBGridColors.SetColor(Index: TKGridColorIndex; Value: TColor); +begin + InternalSetColor(Index, Value); +end; + +{ TKCustomDBGrid } + +constructor TKCustomDBGrid.Create(AOwner: TComponent); +begin + FDataLink := TKDBGridDataLink.Create(Self); + inherited; + FActiveRecord := -1; + FDBOptions := cDBOptionsDef; + FColors.Free; + FColors := TKDBGridColors.Create(Self); + CellClass := TKDBGridCell; + CellPainterClass := TKDBGridCellPainter; + ColClass := TKDBGridCol; + RealizeColClass; +end; + +destructor TKCustomDBGrid.Destroy; +begin + inherited; + FDataLink.Free; +end; + +function TKCustomDBGrid.BeginRowDrag(var Origin: Integer; + const MousePt: TPoint): Boolean; +begin + // does nothing + Result := False; +end; + +procedure TKCustomDBGrid.BeforeCellUpdate(ACol, ARow: Integer); +begin + if FDataLink.Active and not FDataLink.ReadOnly then + begin + InternalSetActiveRecord(ARow - FixedRows); + FDataLink.Edit; + FDataLink.Modified := True; + end; +end; + +procedure TKCustomDBGrid.Changed; +begin + inherited; + FDataLink.Edit; + FDataLink.Modified := True; +end; + +procedure TKCustomDBGrid.ClearCol(ACol: Integer); +begin + // does nothing +end; + +procedure TKCustomDBGrid.ClearGrid; +begin + // does nothing +end; + +procedure TKCustomDBGrid.ClearRow(ARow: Integer); +begin + // does nothing +end; + +procedure TKCustomDBGrid.ColMoved(FromIndex, ToIndex: Integer); +begin + inherited; + DataChanged; +end; + +procedure TKCustomDBGrid.Commit; +begin + if Assigned(FDataLink.DataSet) and FDataLink.Modified then + FDataLink.DataSet.Post; +end; + +function TKCustomDBGrid.CustomSortRows(ByCol: Integer; var SortMode: TKGridSortMode): Boolean; +begin + if Assigned(FDataLink.DataSet) and FDataLink.Active then + begin + Commit; + Result := inherited CustomSortRows(ByCol, SortMode); + if Result then + ClearSortModeVert + else + SortMode := smNone; + end else + begin + ClearSortModeHorz; + Result := False; + end; +end; + +procedure TKCustomDBGrid.DataChanged; +var + I, Index, J, Tmp, LastRow: Integer; + S: WideString; + ADataType: TFieldType; + Cell: TKGridCell; +begin + if Assigned(FDataLink.DataSet) and not Flag(cGF_DBDataUpdating) then + begin + FlagSet(cGF_DBDataUpdating); + try + if FDataLink.Active then + begin + RowCount := FixedRows + FDataLink.DataSet.RecordCount; + if FixedCols + FDataLink.DataSet.FieldCount <> ColCount then + begin + ClearSortMode; + ColCount := FixedCols + FDataLink.DataSet.FieldCount; + for I := 0 to ColCount - 1 do + Cols[I].InitialPos := I; + end; + if FDataLink.DataSet.RecNo >= 1 then + begin + Tmp := FixedRows + FDataLink.DataSet.RecNo - 1; + if not Flag(cGF_DBInternalChanging) and (Row <> Tmp) then + begin + if dboAutoMoveRecord in FDBOptions then + Row := Tmp + else + EditorMode := False; + end; + end; + LastRow := Min(LastVisibleRow + 1, RowCount - 1); + // here memory only grows. I don't know if it is possible to make this more memory effective + FDataLink.BufferCount := Max(FDataLink.BufferCount, Max(LastRow, FDataLink.DataSet.RecNo - 1) + 1); + if (dboIndexFixedCol in FDBOptions) and (FixedCols > 0) then + begin + Cell := InternalGetCell(0, 0); + if Cell is TKDBGridCell then + TKDBGridCell(Cell).Text := SKDBGridIndex; + end; + Tmp := FDataLink.ActiveRecord; + try + for I := FixedCols to ColCount - 1 do + begin + Index := Cols[I].InitialPos; + if Index < ColCount then + begin + S := FDataLink.DataSet.FieldDefs[Index - FixedCols].Name; + ADataType := FDataLink.DataSet.FieldDefs[Index - FixedCols].DataType; + if Cols[I] is TKDBGridCol then + begin + TKDBGridCol(Cols[I]).FName := S; + TKDBGridCol(Cols[I]).FDataType := ADataType; + end; + if dboColNamesToHeader in FDBOptions then + begin + Cell := InternalGetCell(I, 0); + if Cell is TKDBGridCell then + TKDBGridCell(Cell).Text := S; + end; + if (dboAutoSizeBooleanCells in FDBOptions) and (ADataType = ftBoolean) then + begin + ColWidths[I] := cCheckBoxFrameSize + CellPainter.HPadding * 2; + Cols[I].CanResize := False; + end; + end; + end; + for J := TopRow to LastRow do + begin + FDataLink.ActiveRecord := J - FixedRows; + if (FDataLink.ActiveRecord <> Tmp) or not FDataLink.Modified then + for I := FixedCols to ColCount - 1 do + begin + Index := Cols[I].InitialPos; + if Index < ColCount then + begin + Cell := InternalGetCell(I, J); + if Cell is TKDBGridCell then + begin + TKDBGridCell(Cell).FieldToCell(FDataLink.DataSet.Fields[Index - FixedCols]); + if Assigned(TKDBGridCell(Cell).Graphic) then + begin + if dboAutoSizeImageCells in FDBOptions then + begin + if ColWidths[I] > 0 then + ColWidths[I] := Max(ColWidths[I], TKDBGridCell(Cell).Graphic.Width + CellPainter.GraphicHPadding * 2); + if RowHeights[J] > 0 then + RowHeights[J] := Max(RowHeights[J], TKDBGridCell(Cell).Graphic.Height + CellPainter.GraphicVPadding * 2); + end; + if dboImageHint in FDBOptions then + Cols[I].CellHint := True; + end; + end; + end; + end; + if (dboIndexFixedCol in FDBOptions) and (FixedCols > 0) then + begin + Cell := InternalGetCell(0, J); + if Cell is TKDBGridCell then + begin + TKDBGridCell(Cell).Text := IntToStr(J - FixedRows + 1); + if Cell is TKGridAttrTextCell then + TKGridAttrTextCell(Cell).HAlign := halRight; + end; + end; + end; + finally + FDataLink.ActiveRecord := Tmp; + end; + if dboIndicateActiveRecord in FDBOptions then + begin + if FDataLink.ActiveRecord <> FActiveRecord then + begin + if FActiveRecord >= 0 then + InvalidateRow(FActiveRecord + FixedRows); + FActiveRecord := FDataLink.ActiveRecord; + InvalidateRow(FActiveRecord + FixedRows); + end; + end; + end else + begin + RowCount := FixedRows + 1; + FMaxRow := FixedRows; + if dboDontClearFixedCells in FDBOptions then Tmp := FixedRows else Tmp := 0; + for I := 0 to ColCount - 1 do + begin + Cols[I].InitialPos := I; + if Cols[I] is TKDBGridCol then + begin + TKDBGridCol(Cols[I]).FName := ''; + TKDBGridCol(Cols[I]).FDataType := ftUnknown; + end; + if not (dboDontClearFixedCells in FDBOptions) or (I >= FixedCols) then + begin + for J := Tmp to RowCount - 1 do + begin + Cell := InternalGetCell(I, J); + if Cell is TKDBGridCell then + TKDBGridCell(Cell).Clear; + end; + end; + end; + ClearSortMode; + FActiveRecord := -1; + end; + finally + FlagClear(cGF_DBDataUpdating); + end; + end; +end; + +procedure TKCustomDBGrid.DataSetScrolled; +begin + DataChanged; +end; + +procedure TKCustomDBGrid.DefaultEditorCreate(ACol, ARow: Integer; var AEditor: TWinControl); +begin + // create custom editors according to table column type + if Cols[ACol] is TKDBGridCol then + case TKDBGridCol(Cols[ACol]).DataType of + ftString, ftWideString, ftInteger, ftSmallInt, ftWord, ftLargeInt, ftFloat, ftCurrency, ftBcd: + begin + AEditor := TEdit.Create(nil); + end; + ftMemo + {$IF DEFINED(FPC) OR DEFINED(COMPILER10_UP)} + , ftWideMemo + {$IFEND} + : + begin + AEditor := TMemo.Create(nil); + end; + ftDate, ftTime, ftDateTime: + begin + AEditor := {$IFDEF FPC}TDateEdit{$ELSE}TDateTimePicker{$ENDIF}.Create(nil); + end; + ftBoolean: + begin + AEditor := TCheckBox.Create(nil); + end; + else + AEditor := nil; + end + else + AEditor := nil; +end; + +procedure TKCustomDBGrid.DefaultEditorDataFromGrid(AEditor: TWinControl; ACol, ARow: Integer; var AssignText: Boolean); +begin + if Cols[ACol] is TKDBGridCol then + case TKDBGridCol(Cols[ACol]).DataType of + ftDate, ftTime, ftDateTime: + if AEditor is {$IFDEF FPC}TDateEdit{$ELSE}TDateTimePicker{$ENDIF} then + begin + {$IFDEF FPC} + TDateEdit(AEditor).Date := + {$ELSE} + TDateTimePicker(AEditor).DateTime := + {$ENDIF} + StrToDateTime(Cells[ACol, ARow]); + AssignText := False; + end; + ftCurrency, ftBcd: + if AEditor is TEdit then + begin + TEdit(AEditor).Text := CurrToStrF(StrToCurrDef(Cells[ACol, ARow], 0), + ffFixed, TKDBGridCol(Cols[ACol]).CurrencyFormat.CurrencyDecimals); + AssignText := False; + end; + ftBoolean: + if AEditor is TCheckBox then + begin + TCheckBox(AEditor).Checked := LowerCase(Cells[ACol, ARow]) = 'true'; + AssignText := False; + end; + end; +end; + +procedure TKCustomDBGrid.DefaultEditorDataToGrid(AEditor: TWinControl; ACol, ARow: Integer; var AssignText: Boolean); +var + I: Int64; + ADataType: TFieldType; +begin + if Cols[ACol] is TKDBGridCol then + begin + ADataType := TKDBGridCol(Cols[ACol]).DataType; + case ADataType of + ftDate, ftTime, ftDateTime: + if AEditor is {$IFDEF FPC}TDateEdit{$ELSE}TDateTimePicker{$ENDIF} then + begin + Cells[ACol, ARow] := DateTimeToStr( + {$IFDEF FPC} + TDateEdit(AEditor).Date); + {$ELSE} + TDateTimePicker(AEditor).DateTime); + {$ENDIF} + AssignText := False; + end; + ftLargeInt, ftInteger, ftSmallInt, ftWord: + if AEditor is TEdit then + begin + I := StrToInt64Def(TEdit(AEditor).Text, 0); + case ADataType of + ftInteger: I := MinMax(I, -MaxInt - 1, MaxInt); + ftSmallInt: I := MinMax(I, -32768, 32767); + ftWord: I := MinMax(I, 0, 65535); + end; + Cells[ACol, ARow] := IntToStr(I); + AssignText := False; + end; + ftFloat: + if AEditor is TEdit then + begin + Cells[ACol, ARow] := FloatToStr(StrToFloatDef(TEdit(AEditor).Text, 0)); + AssignText := False; + end; + ftCurrency, ftBcd: + if AEditor is TEdit then + begin + Cells[ACol, ARow] := CurrToStrF(StrToCurrDef(TEdit(AEditor).Text, 0), + ffFixed, TKDBGridCol(Cols[ACol]).CurrencyFormat.CurrencyDecimals); + AssignText := False; + end; + ftBoolean: + if AEditor is TCheckBox then + begin + if TCheckBox(AEditor).Checked then + Cells[ACol, ARow] := 'True' + else + Cells[ACol, ARow] := 'False'; + AssignText := False; + end; + end; + end; +end; + +procedure TKCustomDBGrid.DefaultEditorResize(AEditor: TWinControl; ACol, ARow: Integer; + var ARect: TRect); +begin + if Cols[ACol] is TKDBGridCol then + case TKDBGridCol(Cols[ACol]).DataType of + ftBoolean: + {$IFNDEF LCLGTK2} + if AEditor is TCheckBox then + Inc(ARect.Left, 2); + {$ENDIF} + end; +end; + +procedure TKCustomDBGrid.DefaultEditorSelect(AEditor: TWinControl; + ACol, ARow: Integer; SelectAll, CaretToLeft, SelectedByMouse: Boolean); +begin + inherited; + if Cols[ACol] is TKDBGridCol then + case TKDBGridCol(Cols[ACol]).DataType of + ftBoolean: + if (AEditor is TCheckBox) and SelectedByMouse then + ThroughClick := True; + end; +end; + +procedure TKCustomDBGrid.DefaultMouseCellHint(ACol, ARow: Integer; + AShow: Boolean); +var + R: TRect; + Extent: TPoint; + ACell: TKGridCell; + AGraphic: TGraphic; +begin + if ColValid(ACol) and Cols[ACol].CellHint then + begin + ACell := Cell[ACol, ARow]; + if ACell is TKDBGridCell then + begin + AGraphic := TKDBGridCell(ACell).Graphic; + if AGraphic <> nil then + begin + if AShow then + begin + if (ARow >= FixedRows) and ((ARow <> FEditorCell.Row) or (ACol <> FEditorCell.Col) or not EditorMode) and + CellRect(ACol, ARow, R, True) then + begin + Extent := MeasureCell(ACol, ARow, R, GetDrawState(ACol, ARow, HasFocus), mpCellExtent); + if (Extent.X > R.Right - R.Left) or (Extent.Y > R.Bottom - R.Top) then + begin + FreeAndNil(FHint); + FHint := TKGraphicHint.Create(nil); + TKGraphicHint(FHint).Graphic := AGraphic; + Inc(R.Left, 10); + Inc(R.Top, 10); + FHint.ShowAt(ClientToScreen(R.TopLeft)); + end; + end; + end else + FreeAndNil(FHint); + end else + inherited; + end else + inherited; + end else + FreeAndNil(FHint); +end; + +procedure TKCustomDBGrid.DeleteCols(At, Count: Integer); +begin + // does nothing +end; + +procedure TKCustomDBGrid.DeleteRow(At: Integer); +begin + if Assigned(FDataLink.DataSet) and RowValid(At) then + begin + InternalSetActiveRecord(At - FixedRows); + FDataLink.DataSet.Delete; + end; +end; + +procedure TKCustomDBGrid.DeleteRows(At, Count: Integer); +begin + // does nothing +end; + +function TKCustomDBGrid.EditorCreate(ACol, ARow: Integer): TWinControl; +begin + if Assigned(FDataLink.DataSet) and FDataLink.Active and + not FDataLink.ReadOnly and (FDataLink.ActiveRecord = ARow - FixedRows) then + Result := inherited EditorCreate(ACol, ARow) + else + Result := nil; +end; + +function TKCustomDBGrid.GetDataSource: TDataSource; +begin + Result := FDataLink.DataSource; +end; + +procedure TKCustomDBGrid.InsertCols(At, Count: Integer); +begin + // does nothing +end; + +procedure TKCustomDBGrid.InsertRow(At: Integer); +begin + if Assigned(FDataLink.DataSet) and RowValid(At) then + begin + InternalSetActiveRecord(At - FixedRows); + FDataLink.DataSet.Insert; + end; +end; + +procedure TKCustomDBGrid.InsertRows(At, Count: Integer); +begin + // does nothing +end; + +function TKCustomDBGrid.InsertSortedCol(out ByRow, ACol: Integer): Boolean; +begin + // does nothing + Result := False; +end; + +function TKCustomDBGrid.InsertSortedRow(out ByCol, ARow: Integer): Boolean; +begin + // does nothing + Result := False; +end; + +procedure TKCustomDBGrid.InternalSetActiveRecord(Value: Integer); +var + IsEditorMode, IsEditorModeActive: Boolean; +begin + if Assigned(FDataLink.DataSet) and (Value <> FDataLink.ActiveRecord) and + not Flag(cGF_EditorUpdating or cGF_DBInternalChanging) then + begin + FlagSet(cGF_DBInternalChanging); + try + IsEditorMode := EditorMode; + IsEditorModeActive := Flag(cGF_EditorModeActive); + EditorMode := False; + Commit; + FDataLink.MoveBy(Value - FDataLink.ActiveRecord); + EditorMode := IsEditorMode; + if IsEditorModeActive then FlagSet(cGF_EditorModeActive); + finally + FlagClear(cGF_DBInternalChanging); + end; + end; +end; + +procedure TKCustomDBGrid.InternalSetColCount(Value: Integer); +begin + if not FDataLink.Active or Flag(cGF_DBDataUpdating) then + inherited; +end; + +procedure TKCustomDBGrid.InternalSetFixedCols(Value: Integer); +begin + if not FDataLink.Active and not Flag(cGF_DBDataUpdating) then + begin + FlagSet(cGF_DBDataUpdating); + try + inherited; + finally + FlagClear(cGF_DBDataUpdating); + end; + end; +end; + +procedure TKCustomDBGrid.InternalSetFixedRows(Value: Integer); +begin + if not FDataLink.Active and not Flag(cGF_DBDataUpdating) then + begin + FlagSet(cGF_DBDataUpdating); + try + inherited; + finally + FlagClear(cGF_DBDataUpdating); + end; + end; +end; + +procedure TKCustomDBGrid.InternalSetRowCount(Value: Integer); +begin + if not FDataLink.Active or Flag(cGF_DBDataUpdating) then + inherited; +end; + +function TKCustomDBGrid.InternalUpdateVirtualGrid: Boolean; +begin + Result := False; +end; + +procedure TKCustomDBGrid.MoveRow(FromIndex, ToIndex: Integer); +begin + // does nothing +end; + +procedure TKCustomDBGrid.RecordChanged; +var + ARow, I, Index: Integer; + Cell: TKGridCell; +begin + if Assigned(FDataLink.DataSet) and not Flag(cGF_DBDataUpdating) then + begin + FlagSet(cGF_DBDataUpdating); + try + ARow := FDataLink.ActiveRecord + FixedRows; + if Assigned(FDataLink.DataSet) and (ARow < RowCount) then + begin + for I := FixedCols to ColCount - 1 do + begin + Index := Cols[I].InitialPos; + Cell := InternalGetCell(I, ARow); + if Cell is TKDBGridCell then + TKDBGridCell(Cell).FieldToCell(FDataLink.DataSet.Fields[Index - FixedCols]); + end; + end; + finally + FlagClear(cGF_DBDataUpdating); + end; + end; +end; + +function TKCustomDBGrid.SelectCell(ACol, ARow: Integer): Boolean; +begin + Result := inherited SelectCell(ACol, ARow); + if Result and (dboAutoMoveRecord in FDBOptions) then + InternalSetActiveRecord(ARow - FixedRows); +end; + +procedure TKCustomDBGrid.SetDataSource(Value: TDataSource); +begin + if Assigned(FDataLink.DataSource) then FDataLink.DataSource.FreeNotification(Self); + FDataLink.DataSource := Value; +end; + +procedure TKCustomDBGrid.SetDBOptions(const Value: TKDBGridOptions); +begin + if Value <> FDBOptions then + begin + FDBOptions := Value; + DataChanged; + end; +end; + +procedure TKCustomDBGrid.TopLeftChanged; +begin + inherited; + DataChanged; +end; + +procedure TKCustomDBGrid.UpdateData; +var + ARow, I, Index: Integer; + Cell: TKGridCell; +begin + if Assigned(FDataLink.DataSet) and FDataLink.Modified and not Flag(cGF_DBDataUpdating) then + begin + FlagSet(cGF_DBDataUpdating); + try + ARow := FDataLink.ActiveRecord + FixedRows; + for I := FixedCols to ColCount - 1 do + begin + Index := Cols[I].InitialPos; + Cell := InternalGetCell(I, ARow); + if Cell is TKDBGridCell then + TKDBGridCell(Cell).FieldFromCell(FDataLink.DataSet.Fields[Index - FixedCols]); + end; + finally + FlagClear(cGF_DBDataUpdating); + end; + end; +end; + +procedure TKCustomDBGrid.UpdateSize; +begin + inherited; + DataChanged; +end; + +end. diff --git a/components/kcontrols/source/kdialogs.pas b/components/kcontrols/source/kdialogs.pas new file mode 100755 index 000000000..af95bbbe1 --- /dev/null +++ b/components/kcontrols/source/kdialogs.pas @@ -0,0 +1,131 @@ +{ @abstract(This unit contains all dialogs supplied with KControls.) + @author(Tomas Krysl (tk@tkweb.eu)) + @created(18 Sep 2009) + @lastmod(14 Oct 2009) + + This unit implements all dialogs supplied with KControls Development Suite. + + Copyright © 2009 Tomas Krysl (tk@@tkweb.eu)

+ + License:
+ This code is distributed as a freeware. You are free to use it as part + of your application for any purpose including freeware, commercial and + shareware applications. The origin of this source code must not be + misrepresented; you must not claim your authorship. You may modify this code + solely for your own purpose. Please feel free to contact the author if you + think your changes might be useful for other users. You may distribute only + the original package. The author accepts no liability for any damage + that may result from using this code. } + +unit KDialogs; + +{$include kcontrols.inc} +{$WEAKPACKAGEUNIT ON} + +interface + +uses + Classes, Controls, Forms, KControls, KPrintPreview, KPrintSetup; + +type + { @abstract(Encapsulates the print preview dialog) } + TKPrintPreviewDialog = class(TComponent) + private + FControl: TKCustomControl; + FPrintPreviewForm: TKPrintPreviewForm; + function GetPrintPreviewForm: TKPrintPreviewForm; + public + { Creates the instance. Assigns default values to properties. } + constructor Create(AOwner: TComponent); override; + { Shows the dialog. } + procedure Show; + { Shows the dialog as modal dialog. } + function Execute: Boolean; + { Specifies the associated preview form. } + property PrintPreviewForm: TKPrintPreviewForm read GetPrintPreviewForm; + published + { Specifies the associated control. } + property Control: TKCustomControl read FControl write FControl; + end; + + { @abstract(Encapsulates the print preview dialog) } + TKPrintSetupDialog = class(TComponent) + private + FControl: TKCustomControl; + FPrintSetupForm: TKPrintSetupForm; + FPreviewDialog: TKPrintPreviewDialog; + FSelAvail: Boolean; + public + { Creates the instance. Assigns default values to properties. } + constructor Create(AOwner: TComponent); override; + { Shows the dialog as modal dialog. } + function Execute: Boolean; + published + { Specifies the associated control. } + property Control: TKCustomControl read FControl write FControl; + { Specifies the preview dialog for the Preview... button. + If not specified, the print setup dialog creates a new one. } + property PreviewDialog: TKPrintPreviewDialog read FPreviewDialog write FPreviewDialog; + { If True, the Selection Only option will be checked (if selection is available + for the control). } + property SelAvail: Boolean read FSelAvail write FSelAvail default True; + end; + +implementation + +{ TKPrintPreviewDialog } + +constructor TKPrintPreviewDialog.Create(AOwner: TComponent); +begin + inherited; + FPrintPreviewForm := nil; + FControl := nil; +end; + +function TKPrintPreviewDialog.Execute; +begin + PrintPreviewForm.Preview.Control := FControl; + PrintPreviewForm.ShowModal; + Result := True; +end; + +function TKPrintPreviewDialog.GetPrintPreviewForm: TKPrintPreviewForm; +begin + if not Assigned(FPrintPreviewForm) then + FPrintPreviewForm := TKPrintPreviewForm.Create(Self); + Result := FPrintPreviewForm; +end; + +procedure TKPrintPreviewDialog.Show; +begin + PrintPreviewForm.Preview.Control := FControl; + PrintPreviewForm.Show; +end; + +{ TKPrintSetupDialog } + +constructor TKPrintSetupDialog.Create(AOwner: TComponent); +begin + inherited; + FControl := nil; + FPrintSetupForm := nil; + FPreviewDialog := nil; + FSelAvail := True; +end; + +function TKPrintSetupDialog.Execute: Boolean; +begin + if Assigned(FControl) then + begin + if not Assigned(FPrintSetupForm) then + FPrintSetupForm := TKPrintSetupForm.Create(Self); + FPrintSetupForm.PageSetup := FControl.PageSetup; + if Assigned(FPreviewDialog) then + FPrintSetupForm.PreviewForm := FPreviewDialog.PrintPreviewForm; + FPrintSetupForm.SelAvail := FSelAvail; + Result := FPrintSetupForm.ShowModal = mrOk; + end else + Result := False; +end; + +end. diff --git a/components/kcontrols/source/keditcommon.pas b/components/kcontrols/source/keditcommon.pas new file mode 100755 index 000000000..b0a64d939 --- /dev/null +++ b/components/kcontrols/source/keditcommon.pas @@ -0,0 +1,413 @@ +{ @abstract(This unit contains the common declarations for all edit controls.) + @author(Tomas Krysl (tk@tkweb.eu)) + @created(18 Sep 2009) + @lastmod(20 Jun 2010) + + This unit defines common types and functions for all edit controls. + + Copyright © 2009 Tomas Krysl (tk@@tkweb.eu)

+ + License:
+ This code is distributed as a freeware. You are free to use it as part + of your application for any purpose including freeware, commercial and + shareware applications. The origin of this source code must not be + misrepresented; you must not claim your authorship. You may modify this code + solely for your own purpose. Please feel free to contact the author if you + think your changes might be useful for other users. You may distribute only + the original package. The author accepts no liability for any damage + that may result from using this code. } + +unit KEditCommon; + +{$include kcontrols.inc} +{$WEAKPACKAGEUNIT ON} + +interface + +uses +{$IFDEF FPC} + LCLType, LCLIntf, LCLProc, LResources, +{$ELSE} + Windows, Messages, +{$ENDIF} + SysUtils, Classes, Graphics, Controls, Forms; + +type + { Declares possible values for the edit control commands. } + TKEditCommand = ( + { Move caret left one char } + ecLeft, + { Move caret right one char } + ecRight, + { Move caret up one line } + ecUp, + { Move caret down one line } + ecDown, + { Move caret to beginning of line } + ecLineStart, + { Move caret to end of line } + ecLineEnd, + { Move caret up one page } + ecPageUp, + { Move caret down one page } + ecPageDown, + { Move caret left one page } + ecPageLeft, + { Move caret right one page } + ecPageRight, + { Move caret to top of page } + ecPageTop, + { Move caret to bottom of page } + ecPageBottom, + { Move caret to absolute beginning } + ecEditorTop, + { Move caret to absolute end } + ecEditorBottom, + { Move caret to specific coordinates, Data = ^TPoint } + ecGotoXY, + { Move caret left one char } + ecSelLeft, + { Move caret right one char, affecting selection } + ecSelRight, + { Move caret up one line, affecting selection } + ecSelUp, + { Move caret down one line, affecting selection } + ecSelDown, + { Move caret to beginning of line, affecting selection } + ecSelLineStart, + { Move caret to end of line, affecting selection } + ecSelLineEnd, + { Move caret up one page, affecting selection } + ecSelPageUp, + { Move caret down one page, affecting selection } + ecSelPageDown, + { Move caret left one page, affecting selection } + ecSelPageLeft, + { Move caret right one page, affecting selection } + ecSelPageRight, + { Move caret to top of page, affecting selection } + ecSelPageTop, + { Move caret to bottom of page, affecting selection } + ecSelPageBottom, + { Move caret to absolute beginning, affecting selection } + ecSelEditorTop, + { Move caret to absolute end, affecting selection } + ecSelEditorBottom, + { Move caret to specific coordinates, affecting selection, Data = ^TPoint } + ecSelGotoXY, + { Scroll up one line leaving caret position unchanged } + ecScrollUp, + { Scroll down one line leaving caret position unchanged } + ecScrollDown, + { Scroll left one char leaving caret position unchanged } + ecScrollLeft, + { Scroll right one char leaving caret position unchanged } + ecScrollRight, + { Scroll to center the caret position within client area } + ecScrollCenter, + { Undo previous action } + ecUndo, + { Redo last undone action } + ecRedo, + { Copy selection to clipboard } + ecCopy, + { Cut selection to clipboard } + ecCut, + { Paste clipboard to current position } + ecPaste, + { Insert character at current position, Data = ^Char } + ecInsertChar, + { Insert digits (digit string) at current position, Data = ^string + (must contain digits only), TKCustomHexEditor only } + ecInsertDigits, + { Insert string (multiple characters) at current position, Data = ^string } + ecInsertString, + { Delete last character (i.e. backspace key) } + ecDeleteLastChar, + { Delete character at caret (i.e. delete key) } + ecDeleteChar, + { Delete from caret to beginning of line } + ecDeleteBOL, + { Delete from caret to end of line } + ecDeleteEOL, + { Delete current line } + ecDeleteLine, + { Select everything } + ecSelectAll, + { Delete everything } + ecClearAll, + { Delete selection (no digit selection), TKCustomHexEditor only } + ecClearIndexSelection, + { Delete selection (digit selection as well) } + ecClearSelection, + { Search for text/digits } + ecSearch, + { Replace text/digits } + ecReplace, + { Set insert mode } + ecInsertMode, + { Set overwrite mode } + ecOverwriteMode, + { Toggle insert/overwrite mode } + ecToggleMode, + { Adjust editor when getting input focus } + ecGotFocus, + { Adjust editor when losing input focus } + ecLostFocus + ); + + { @abstract(Declares the keystroke information structure for the Key member + of the @link(TKEditCommandAssignment) structure) +
    + Members: +
  • Key - virtual key code
  • +
  • Shift - shift state that belongs to that key code
  • +
+ } + TKEditKey = record + Key: Word; + Shift: TShiftState; + end; + + { @abstract(Declares the @link(TKEditKeyMapping) array item) +
    + Members: +
  • Command - command that is about to be executed
  • +
  • Key - key combination necessary to execute that command
  • +
+ } + TKEditCommandAssignment = record + Command: TKEditCommand; + Key: TKEditKey; + end; + + { @abstract(Declares OnDropFiles event handler) +
    + Parameters: +
  • Sender - identifies the event caller
  • +
  • X, Y - mouse cursor coordinates (relative to the caller's window)
  • +
  • Files - list of file names that were dropped on the caller's window)
  • +
+ } + TKEditDropFilesEvent = procedure(Sender: TObject; X, Y: integer; + Files: TStrings) of object; + + { Declares key mapping array for the KeyMapping property } + TKEditKeyMapping = array of TKEditCommandAssignment; + + { Declares character mapping array for the @link(TKCustomHexEditor.CharMapping) property } + TKEditCharMapping = array of AnsiChar; + + { Pointer to @link(TKHexEditorCharMapping) } + PKEditCharMapping = ^TKEditCharMapping; + + { Declares options - possible values for the @link(TKCustomEdit.Options) property } + TKEditOption = ( + { The editor will receive dropped files } + eoDropFiles, + { All undo/redo operations of the same kind will be grouped together } + eoGroupUndo, + { The editor allows undo/redo operations after the @link(TKCustomEdit.Modified) property + has been set to False } + eoUndoAfterSave + ); + + { Options can be arbitrary combined } + TKEditOptions = set of TKEditOption; + + { Declares possible values for the Action parameter in the @link(TKEditReplaceTextEvent) event } + TKEditReplaceAction = ( + { Quit replace sequence } + eraCancel, + { Replace this occurence } + eraYes, + { Don't replace this occurence } + eraNo, + { Replace all following occurences without prompting } + eraAll + ); + + { @abstract(Declares OnReplaceText event handler) +
    + Parameters: +
  • Sender - identifies the event caller
  • +
  • TextToFind - current search string
  • +
  • TextToReplace - current replace string
  • +
  • Action - specifies how the replace function should continue
  • +
+ } + TKEditReplaceTextEvent = procedure(Sender: TObject; const TextToFind, TextToReplace: + string; var Action: TKEditReplaceAction) of object; + + { Declares possible values for the ErrorReason member of the @link(TKEditSearchData) structure } + TKEditSearchError = ( + { No error occured } + eseOk, + { There is a character in the search string that cannot be interpreted as hexadecimal digits} + eseNoDigitsFind, + { There is a character in the replace string that cannot be interpreted as hexadecimal digits} + eseNoDigitsReplace, + { No other search string found } + eseNoMatch + ); + + { Declares search options - possible values for the Options member of the @link(TKEditSearchData) structure } + TKEditSearchOption = ( + { Replace all occurences } + esoAll, + { Search backwards } + esoBackwards, + { Search entire scope instead from current caret position } + esoEntireScope, + { Include to identify search - this element will be automatically cleared + to provide the @link(TKEditSearchData) structure for additional search } + esoFirstSearch, + { Match case when a binary search should be executed } + esoMatchCase, + { Prompt user before a string is about to be replaced. This assumes @link(OnReplaceText) + is assigned } + esoPrompt, + { Search the current selection only } + esoSelectedOnly, + { Treat the supplied search and/or replace strings as hexadecimal sequence. + When the search string contains a character that cannot be interpreted as + hexadecimal digit, the execution stops and @link(eseNoDigits) error will + be returned. Similarly, @link(eseNoDigitsReplace) errors will be returned + on invalid replace string } + esoTreatAsDigits, + { Internal option - don't modify } + esoWereDigits + ); + + { Search options can be arbitrary combined } + TKEditSearchOptions = set of TKEditSearchOption; + + { @abstract(Declares the search/replace description structure for the @link(ecSearch) + and @link(ecReplace) commands) +
    + Members: +
  • ErrorReason - upon @link(ExecuteCommand)(ecSearch) or + ExecuteCommand(ecReplace), inspect this member to inform user about + search/replace result
  • +
  • Options - defines search/replace options
  • +
  • SelStart, SelEnd - internal parameters, don't modify
  • +
  • TextToFind - search string
  • +
  • TextToReplace - replace string
  • +
+ } + TKEditSearchData = record + ErrorReason: TKEditSearchError; + Options: TKEditSearchOptions; + SelStart, + SelEnd: Integer; + TextToFind, + TextToReplace: string; + end; + + { Pointer to @link(TKEditSearchData) } + PKEditSearchData = ^TKEditSearchData; + +{ Returns default key mapping structure } +function CreateDefaultKeyMapping: TKEditKeyMapping; + +{ Returns default char mapping structure } +function DefaultCharMapping: TKEditCharMapping; + +{ Returns default search data structure } +function DefaultSearchData: TKEditSearchData; + +implementation + +function CreateDefaultKeyMapping: TKEditKeyMapping; + + procedure AddKey(Command: TKEditCommand; Key: Word; Shift: TShiftState); + var + I: Integer; + begin + I := Length(Result); + SetLength(Result, I + 1); + Result[I].Command := Command; + Result[I].Key.Key := Key; + Result[I].Key.Shift := Shift; + end; + +begin + AddKey(ecLeft, VK_LEFT, []); + AddKey(ecRight, VK_RIGHT, []); + AddKey(ecRight, VK_RETURN, []); + AddKey(ecUp, VK_UP, []); + AddKey(ecDown, VK_DOWN, []); + AddKey(ecLineStart, VK_HOME, []); + AddKey(ecLineEnd, VK_END, []); + AddKey(ecPageUp, VK_PRIOR, []); + AddKey(ecPageDown, VK_NEXT, []); + AddKey(ecPageLeft, VK_LEFT, [ssCtrl, ssAlt]); + AddKey(ecPageRight, VK_RIGHT, [ssCtrl, ssAlt]); + AddKey(ecPageTop, VK_PRIOR, [ssCtrl]); + AddKey(ecPageBottom, VK_NEXT, [ssCtrl]); + AddKey(ecEditorTop, VK_HOME, [ssCtrl]); + AddKey(ecEditorBottom, VK_END, [ssCtrl]); + AddKey(ecSelLeft, VK_LEFT, [ssShift]); + AddKey(ecSelRight, VK_RIGHT, [ssShift]); + AddKey(ecSelUp, VK_UP, [ssShift]); + AddKey(ecSelDown, VK_DOWN, [ssShift]); + AddKey(ecSelLineStart, VK_HOME, [ssShift]); + AddKey(ecSelLineEnd, VK_END, [ssShift]); + AddKey(ecSelPageUp, VK_PRIOR, [ssShift]); + AddKey(ecSelPageDown, VK_NEXT, [ssShift]); + AddKey(ecSelPageLeft, VK_LEFT, [ssShift, ssCtrl, ssAlt]); + AddKey(ecSelPageRight, VK_RIGHT, [ssShift, ssCtrl, ssAlt]); + AddKey(ecSelPageTop, VK_PRIOR, [ssShift, ssCtrl]); + AddKey(ecSelPageBottom, VK_NEXT, [ssShift, ssCtrl]); + AddKey(ecSelEditorTop, VK_HOME, [ssShift, ssCtrl]); + AddKey(ecSelEditorBottom, VK_END, [ssShift, ssCtrl]); + AddKey(ecScrollUp, VK_UP, [ssCtrl]); + AddKey(ecScrollDown, VK_DOWN, [ssCtrl]); + AddKey(ecScrollLeft, VK_LEFT, [ssCtrl]); + AddKey(ecScrollRight, VK_RIGHT, [ssCtrl]); + AddKey(ecScrollCenter, VK_RETURN, [ssCtrl]); + AddKey(ecUndo, ord('Z'), [ssCtrl]); + AddKey(ecUndo, VK_BACK, [ssAlt]); + AddKey(ecRedo, ord('Z'), [ssShift, ssCtrl]); + AddKey(ecRedo, VK_BACK, [ssShift, ssAlt]); + AddKey(ecCopy, ord('C'), [ssCtrl]); + AddKey(ecCopy, VK_INSERT, [ssCtrl]); + AddKey(ecCut, ord('X'), [ssCtrl]); + AddKey(ecCut, VK_DELETE, [ssShift]); + AddKey(ecPaste, ord('V'), [ssCtrl]); + AddKey(ecPaste, VK_INSERT, [ssShift]); + AddKey(ecDeleteLastChar, VK_BACK, []); + AddKey(ecDeleteLastChar, VK_BACK, [ssShift]); + AddKey(ecDeleteChar, VK_DELETE, []); + AddKey(ecDeleteEOL, ord('Y'), [ssCtrl,ssShift]); + AddKey(ecDeleteLine, ord('Y'), [ssCtrl]); + AddKey(ecSelectAll, ord('A'), [ssCtrl]); + AddKey(ecToggleMode, VK_INSERT, []); +end; + +function DefaultCharMapping: TKEditCharMapping; +var + I: Integer; +begin + SetLength(Result, 256); + for I := 0 to Length(Result) - 1 do + if (I < $20) or (I >= $80) then + Result[I] := '.' + else + Result[I] := AnsiChar(I); +end; + +function DefaultSearchData: TKEditSearchData; +begin + with Result do + begin + ErrorReason := eseOk; + Options := [esoAll, esoFirstSearch, esoPrompt, esoTreatAsDigits]; + SelStart := 0; + SelEnd := 0; + TextToFind := ''; + TextToReplace := ''; + end; +end; + +end. diff --git a/components/kcontrols/source/kfunctions.pas b/components/kcontrols/source/kfunctions.pas new file mode 100755 index 000000000..8fc6ea2e8 --- /dev/null +++ b/components/kcontrols/source/kfunctions.pas @@ -0,0 +1,1365 @@ +{ @abstract(This unit contains miscellaneous supporting functions) + @author(Tomas Krysl (tk@tkweb.eu)) + @created(20 Oct 2001) + @lastmod(20 Jun 2010) + + Copyright © 2001 Tomas Krysl (tk@@tkweb.eu)

+ + License:
+ This code is distributed as a freeware. You are free to use it as part + of your application for any purpose including freeware, commercial and + shareware applications. The origin of this source code must not be + misrepresented; you must not claim your authorship. You may modify this code + solely for your own purpose. Please feel free to contact the author if you + think your changes might be useful for other users. You may distribute only + the original package. The author accepts no liability for any damage + that may result from using this code. } + +unit KFunctions; + +{$include kcontrols.inc} +{$WEAKPACKAGEUNIT ON} + +interface + +uses +{$IFDEF FPC} + // use the LCL interface support whenever possible + {$IFDEF USE_WINAPI} + Windows, + {$ENDIF} + LCLType, LCLIntf, LMessages, LCLProc, LCLVersion, +{$ELSE} + Windows, Messages, +{$ENDIF} + Classes, Controls, ComCtrls, Graphics; + +const +{$IFNDEF FPC} + { @exclude } + KM_MOUSELEAVE = WM_MOUSELEAVE; + { @exclude } + LM_USER = WM_USER; + { @exclude } + LM_CANCELMODE = WM_CANCELMODE; + { @exclude } + LM_CHAR = WM_CHAR; + { @exclude } + LM_DROPFILES = WM_DROPFILES; + { @exclude } + LM_ERASEBKGND = WM_ERASEBKGND; + { @exclude } + LM_GETDLGCODE = WM_GETDLGCODE; + { @exclude } + LM_HSCROLL = WM_HSCROLL; + { @exclude } + LM_KEYDOWN = WM_KEYDOWN; + { @exclude } + LM_KILLFOCUS = WM_KILLFOCUS; + { @exclude } + LM_LBUTTONDOWN = WM_LBUTTONDOWN; + { @exclude } + LM_LBUTTONUP = WM_LBUTTONUP; + { @exclude } + LM_MOUSEMOVE = WM_MOUSEMOVE; + { @exclude } + LM_SETFOCUS = WM_SETFOCUS; + { @exclude } + LM_SIZE = WM_SIZE; + { @exclude } + LM_VSCROLL = WM_VSCROLL; + { @exclude } + LCL_MAJOR = 0; + { @exclude } + LCL_MINOR = 0; + { @exclude } + LCL_RELEASE = 0; + +{$ELSE} + // hope this is correct about WM_MOUSELEAVE otherwise adapt it as you wish + {$IFDEF LCLWin32} + {$IF ((LCL_MAJOR=0) AND (LCL_MINOR=9) AND (LCL_RELEASE<27))} + { @exclude } + KM_MOUSELEAVE = LM_LEAVE; // LCL 0.9.26.2- + {$ELSE} + { @exclude } + KM_MOUSELEAVE = LM_MOUSELEAVE; // LCL 0.9.27+ + {$IFEND} + {$ELSE} + {$IFDEF LCLWinCE} + { @exclude } + KM_MOUSELEAVE = LM_LEAVE; + {$ELSE} + { @exclude } + KM_MOUSELEAVE = LM_MOUSELEAVE; + {$ENDIF} + {$ENDIF} + { @exclude } + //WM_CTLCOLORBTN = Messages.WM_CTLCOLORBTN; + { @exclude } + //WM_CTLCOLORSTATIC = Messages.WM_CTLCOLORSTATIC; +{$ENDIF} + +{$IFDEF USE_WINAPI} + { @exclude } + SHFolderDll = 'SHFolder.dll'; +{$ENDIF} + + { Base for custom messages used by KControls suite. } + KM_BASE = LM_USER + 1024; + + { Custom message. } + KM_LATEUPDATE = KM_BASE + 1; + + { Constant for horizontal resize cursor. } + crHResize = TCursor(101); + { Constant for vertical resize cursor. } + crVResize = TCursor(102); + { Constant for uncaptured dragging cursor. } + crDragHandFree = TCursor(103); + { Constant for captured dragging cursor. } + crDragHandGrip = TCursor(104); + + { Checkbox frame size in logical screen units. } + cCheckBoxFrameSize = 13; + + { Set of word break characters. } + cWordBreaks = [#0, #9, #32]; + { Set of line break characters. } + cLineBreaks = [#10, #13]; + { Carriage return character. } + cCR = #10; + { Line feed character. } + cLF = #13; + { Text ellipsis string. } + cEllipsis = '...'; + +type +{$IFNDEF FPC} + { @exclude } + TLMessage = TMessage; + { @exclude } + TLMMouse = TWMMouse; + { @exclude } + TLMNoParams = TWMNoParams; + { @exclude } + TLMKey = TWMKey; + { @exclude } + TLMChar = TWMChar; + { @exclude } + TLMEraseBkGnd = TWMEraseBkGnd; + { @exclude } + TLMHScroll = TWMHScroll; + { @exclude } + TLMKillFocus = TWMKillFocus; + { @exclude } + TLMSetFocus = TWMSetFocus; + { @exclude } + TLMSize = TWMSize; + { @exclude } + TLMVScroll = TWMVScroll; +{$ENDIF} + + //PInteger = ^Integer; defined by System.pas + { Static array for Integer. } + TIntegers = array[0..MaxInt div SizeOf(Integer) - 1] of Integer; + { Pointer for TIntegers. } + PIntegers = ^TIntegers; + { Dynamic array for Integer. } + TDynIntegers = array of Integer; + + //PCardinal = ^Cardinal; defined by System.pas + { Static array for Cardinal. } + TCardinals = array[0..MaxInt div SizeOf(Cardinal) - 1] of Cardinal; + { Pointer for TCardinals. } + PCardinals = ^TCardinals; + { Dynamic array for Cardinal. } + TDynCardinals = array of Cardinal; + + //PShortInt = ^ShortInt; defined by System.pas + { Static array for ShortInt. } + TShortInts = array[0..MaxInt div SizeOf(ShortInt) - 1] of ShortInt; + { Pointer for TShortInts. } + PShortInts = ^TShortInts; + { Dynamic array for ShortInt. } + TDynShortInts = array of ShortInt; + + //PSmallInt = ^SmallInt; defined by System.pas + { Static array for SmallInt. } + TSmallInts = array[0..MaxInt div SizeOf(SmallInt) - 1] of SmallInt; + { Pointer for TSmallInts. } + PSmallInts = ^TSmallInts; + { Dynamic array for SmallInt. } + TDynSmallInts = array of SmallInt; + + //PLongInt = ^LongInt; defined by System.pas + { Static array for LongInt. } + TLongInts = array[0..MaxInt div SizeOf(LongInt) - 1] of LongInt; + { Pointer for TLongInts. } + PLongInts = ^TLongInts; + { Dynamic array for LongInt. } + TDynLongInts = array of LongInt; + + //PInt64 = ^Int64; defined by System.pas + { Static array for Int64. } + TInt64s = array[0..MaxInt div SizeOf(Int64) - 1] of Int64; + { Pointer for TInt64s. } + PInt64s = ^TInt64s; + { Dynamic array for Int64. } + TDynInt64s = array of Int64; + + //PByte = ^Byte; defined by System.pas + { Static array for Byte. } + TBytes = array[0..MaxInt div SizeOf(Byte) - 1] of Byte; + { Pointer for TBytes. } + PBytes = ^TBytes; + { Dynamic array for Byte. } + TDynBytes = array of Byte; + + //PWord = ^Word; defined by System.pas + { Static array for Word. } + TWords = array[0..MaxInt div SizeOf(Word) - 1] of Word; + { Pointer for TWords. } + PWords = ^TWords; + { Dynamic array for Word. } + TDynWords = array of Word; + + //PLongWord = ^LongWord; defined by System.pas + { Static array for LongWord. } + TLongWords = array[0..MaxInt div SizeOf(LongWord) - 1] of LongWord; + { Pointer for TLongWords. } + PLongWords = ^TLongWords; + { Dynamic array for LongWord. } + TDynLongWords = array of LongWord; + +{$IFDEF COMPILER10_UP} + { Static array for UInt64. } + TUInt64s = array[0..MaxInt div SizeOf(UInt64) - 1] of UInt64; + { Pointer for TUInt64s. } + PUInt64s = ^TUInt64s; + { Dynamic array for UInt64. } + TDynUInt64s = array of UInt64; +{$ENDIF} + + //PSingle = ^Single; defined by System.pas + { Static array for Single. } + TSingles = array[0..MaxInt div SizeOf(Single) - 1] of Single; + { Pointer for TSingles. } + PSingles = ^TSingles; + { Dynamic array for Single. } + TDynSingles = array of Single; + + //PDouble = ^Double; defined by System.pas + { Static array for Double. } + TDoubles = array[0..MaxInt div SizeOf(Double) - 1] of Double; + { Pointer for TDoubles. } + PDoubles = ^TDoubles; + { Dynamic array for Double. } + TDynDoubles = array of Double; + +{$IFNDEF FPC} + //PExtended = ^Extended; defined by System.pas + { Static array for Extended. } + TExtendeds = array[0..MaxInt div SizeOf(Extended) - 1] of Extended; + { Pointer for TExtendeds. } + PExtendeds = ^TExtendeds; + { Dynamic array for Extended. } + TDynExtendeds = array of Extended; +{$ENDIF} + + //PChar is special type + { Static array for Char. } + TChars = array[0..MaxInt div SizeOf(Char) - 1] of Char; + { Pointer for TChars. } + PChars = ^TChars; + { Dynamic array for Char. } + TDynChars = array of Char; + + { Useful structure to handle general data and size as a single item } + TDataSize = record + Data: Pointer; + Size: Integer; + end; + { Pointer for TDataSize } + PDataSize = ^TDataSize; + + { Set type for @link(CharInSetEx). } + TKSysCharSet = set of AnsiChar; + + { Defines a currency format settings for @link(FormatCurrency). } + TKCurrencyFormat = record + CurrencyFormat, + CurrencyDecimals: Byte; + CurrencyString: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; + DecimalSep: Char; + ThousandSep: Char; + UseThousandSep: Boolean; + end; + +{ Replaces possible decimal separators in S with DecimalSeparator variable.} +function AdjustDecimalSeparator(const S: string): string; + +{$IFNDEF FPC} +{ Converts an AnsiString into a PWideChar string. If CodePage is not set + the current system code page for ANSI-UTFx translations will be used. } +function AnsiStringToWideChar(const Text: AnsiString; CodePage: Cardinal = CP_ACP): PWideChar; +{$ENDIF} + +{ Under Windows this function calls the WinAPI TrackMouseEvent. Under other OSes + the implementation is still missing. } +procedure CallTrackMouseEvent(Control: TWinControl; var Status: Boolean); + +{ Compiler independent Delphi2009-like CharInSet function for ANSI characters. } +function CharInSetEx(AChar: AnsiChar; const ASet: TKSysCharSet): Boolean; overload; + +{ Compiler independent Delphi2009-like CharInSet function for Unicode characters. } +function CharInSetEx(AChar: WideChar; const ASet: TKSysCharSet): Boolean; overload; + +{ Compares two Integers. Returns 1 if I1 > I2, -1 if I1 < I2 and 0 if I1 = I2. } +function CompareIntegers(I1, I2: Integer): Integer; + +{ Compares two PWideChar strings. Returns 1 if W1 > W2, -1 if W1 < W2 and + 0 if W1 = W2. The strings will be compared using the default user locale + unless another locale has been specified in Locale. } +function CompareWideChars(W1, W2: PWideChar{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal = LOCALE_USER_DEFAULT{$ENDIF}): Integer; + +{$IFDEF STRING_IS_UNICODE} +{ Compares two Unicode strings (Lazarus, Delphi 2009 and better). Returns 1 if S1 > S2, + -1 if S1 < S2 and 0 if S1 = S2. The strings will be compared using the default + user locale unless another locale has been specified in Locale. } +function CompareChars(S1, S2: PChar{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal = LOCALE_USER_DEFAULT{$ENDIF}): Integer; +{$ENDIF} + +{ Compares two WideString strings. Returns 1 if W1 > W2, -1 if W1 < W2 and + 0 if W1 = W2. The strings will be compared using the default user locale + unless another locale has been specified in Locale. } +function CompareWideStrings(W1, W2: WideString{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal = LOCALE_USER_DEFAULT{$ENDIF}): Integer; + +{$IFDEF STRING_IS_UNICODE} +{ Compares two Unicode strings (Lazarus, Delphi 2009 and better). Returns 1 if S1 > S2, + -1 if S1 < S2 and 0 if S1 = S2. The strings will be compared using the default + user locale unless another locale has been specified in Locale. } +function CompareStrings(S1, S2: string{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal = LOCALE_USER_DEFAULT{$ENDIF}): Integer; +{$ENDIF} + +{ Performs integer division. If there is a nonzero remainder, + the result will be incremented. } +function DivUp(Dividend, Divisor: Integer): Integer; + +{ Performs integer division. If there is a nonzero remainder, + the result will be decremented. } +function DivDown(Dividend, Divisor: Integer): Integer; + +{ Raises a general exception with associated message Msg. } +procedure Error(const Msg: string); + +{ Swaps values of two SmallInt variables. } +procedure Exchange(var Value1, Value2: SmallInt); overload; +{ Swaps values of two ShortInt variables. } +procedure Exchange(var Value1, Value2: ShortInt); overload; +{ Swaps values of two Integer variables. } +procedure Exchange(var Value1, Value2: Integer); overload; +{ Swaps values of two Int64 variables. } +procedure Exchange(var Value1, Value2: Int64); overload; +{ Swaps values of two Byte variables. } +procedure Exchange(var Value1, Value2: Byte); overload; +{ Swaps values of two Word variables. } +procedure Exchange(var Value1, Value2: Word); overload; +{ Swaps values of two Cardinal variables. } +procedure Exchange(var Value1, Value2: Cardinal); overload; +{$IFDEF COMPILER10_UP } +{ Swaps values of two UInt64 variables. } +procedure Exchange(var Value1, Value2: UInt64); overload; +{$ENDIF} +{ Swaps values of two Single variables. } +procedure Exchange(var Value1, Value2: Single); overload; +{ Swaps values of two Double variables. } +procedure Exchange(var Value1, Value2: Double); overload; +{$IFNDEF FPC} +{ Swaps values of two Extended variables. } +procedure Exchange(var Value1, Value2: Extended); overload; +{$ENDIF} +{ Swaps values of two Char variables. } +procedure Exchange(var Value1, Value2: Char); overload; + +{ Fills the message record. } +function FillMessage(Msg: Cardinal; WParam: WPARAM; LParam: LPARAM): TLMessage; + +{ Formats the given currency value with to specified parameters. Not thread safe. } +function FormatCurrency(Value: Currency; const AFormat: TKCurrencyFormat): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; + +{ Returns the module version for given module. Works under WinX only. } +function GetAppVersion(const ALibName: string; var MajorVersion, MinorVersion, BuildNumber, RevisionNumber: Word): Boolean; + +{ Returns the Text property of any TWinControl instance as WideString (up to Delphi 2007) + or string (Delphi 2009, Lazarus). } +function GetControlText(Value: TWinControl): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; + +{ Returns current status of Shift, Alt and Ctrl keys. } +function GetShiftState: TShiftState; + +{ Converts an integer into binary string with custom alignment + (given by Digits). } +function IntToAscii(Value: Int64; Digits: Integer): string; +{ Converts an integer into binary digit string with custom alignment + (given by Digits) and suffix. } +function IntToBinStr(Value: Int64; Digits: Byte; const Suffix: string): string; +{ Converts an integer value into BCD number. } +function IntToBCD(Value: Cardinal): Cardinal; +{ Converts an integer into decimal digit string. Equals to IntToStr. } +function IntToDecStr(Value: Int64): string; +{ Converts an integer into hexadecimal digit string with custom alignment + (given by Digits), prefix and suffix. Digits represented by alphabetical + characters can be either in lower or upper case. } +function IntToHexStr(Value: Int64; Digits: Byte; const Prefix, Suffix: string; + UseLowerCase: Boolean): string; + +function IntPowerInt(Value: Int64; Exponent: Integer): Int64; + +{ Converts a binary string into integer with custom alignment (given by Digits). } +function AsciiToInt(S: string; Digits: Integer): Int64; +{ Converts a BCD number into integer value. } +function BCDToInt(Value: Cardinal): Cardinal; +{ Converts a binary digit string into integer with custom alignment + (given by Digits) and sign of a value represented by the string (given by Signed). + Code returns either zero for a successful conversion or the position of + first bad character. } +function BinStrToInt(S: string; Digits: Byte; Signed: Boolean; + var Code: Integer): Int64; +{ Converts a decimal digit string into integer. Code returns either zero for + a successful conversion or the position of first bad character. Equals to Val. } +function DecStrToInt(S: string; var Code: Integer): Int64; +{ Converts a hexadecimal digit string into integer with custom alignment + (given by Digits) and sign of a value represented by the string (given by Signed). + Code returns either zero for a successful conversion or the position of + first bad character. } +function HexStrToInt(S: string; Digits: Byte; Signed: Boolean; + var Code: Integer): Int64; + +{ Returns a clipped ShortInt value so that it lies between Min and Max } +function MinMax(Value, Min, Max: ShortInt): ShortInt; overload; +{ Returns a clipped SmallInt value so that it lies between Min and Max } +function MinMax(Value, Min, Max: SmallInt): SmallInt; overload; +{ Returns a clipped Integer value so that it lies between Min and Max } +function MinMax(Value, Min, Max: Integer): Integer; overload; +{ Returns a clipped Int64 value so that it lies between Min and Max } +function MinMax(Value, Min, Max: Int64): Int64; overload; +{ Returns a clipped Single value so that it lies between Min and Max } +function MinMax(Value, Min, Max: Single): Single; overload; +{ Returns a clipped Double value so that it lies between Min and Max } +function MinMax(Value, Min, Max: Double): Double; overload; +{$IFNDEF FPC} +{ Returns a clipped Extended value so that it lies between Min and Max } +function MinMax(Value, Min, Max: Extended): Extended; overload; +{$ENDIF} + +{ Under Windows this function calls the WinAPI SetWindowRgn. Under other OSes + the implementation is still missing. } +procedure SetControlClipRect(AControl: TWinControl; const ARect: TRect); + +{ Modifies the Text property of any TWinControl instance. The value is given as + WideString (up to Delphi 2007) or string (Delphi 2009, Lazarus). } +procedure SetControlText(Value: TWinControl; const Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); + +{ Returns next character index for given null terminated string and character index. + Takes MBCS (UTF8 in Lazarus) into account. } +function StrNextCharIndex(AText: {$IFDEF STRING_IS_UNICODE}PChar{$ELSE}PWideChar{$ENDIF}; Index: Integer): Integer; + +{ Returns the index for given string where character at given index begins. + Takes MBCS (UTF8 in Lazarus) into account. } +function StringCharBegin(const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; Index: Integer): Integer; + +{ Returns the number of characters in a string. Under Delphi it equals Length, + under Lazarus it equals UTF8Length. } +function StringLength(const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}): Integer; + +{ Returns next character index for given string and character index. + Takes MBCS (UTF8 in Lazarus) into account. } +function StringNextCharIndex(const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; Index: Integer): Integer; + +{ Trims characters specified by ASet from the beginning and end of AText. + New text length is returned by ALen. } +procedure TrimWhiteSpaces(var AText: {$IFDEF STRING_IS_UNICODE}PChar{$ELSE}PWideChar{$ENDIF}; var ALen: Integer; const ASet: TKSysCharSet); overload; + +{ Trims characters specified by ASet from the beginning and end of AText. } +procedure TrimWhiteSpaces(var AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; const ASet: TKSysCharSet); overload; + +{$IFNDEF FPC} +{ Converts a PWideChar string into AnsiString. If CodePage is not set + the current system code page for ANSI-UTFx translations will be used. } +function WideCharToAnsiString(Text: PWideChar; CodePage: Cardinal = CP_ACP): AnsiString; +{$ENDIF} + +{$IFDEF USE_WINAPI} +function GetWindowsFolder(CSIDL: Cardinal; var APath: string): Boolean; +{$ENDIF} + +implementation + +uses + Forms, Math, SysUtils, TypInfo +{$IFDEF USE_WINAPI} + , ShlObj +{$ENDIF} +{$IFDEF USE_WIDEWINPROCS} + , KWideWinProcs +{$ENDIF} +; + +function AdjustDecimalSeparator(const S: string): string; +var + I: Integer; +begin + Result := S; + for I := 1 to Length(Result) do + if CharInSetEx(Result[I], [',', '.']) then + Result[I] := DecimalSeparator; +end; + +{$IFNDEF FPC} +function AnsiStringToWideChar(const Text: AnsiString; CodePage: Cardinal): PWideChar; +var + Len: Integer; +begin + Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(Text), -1, nil, 0); + GetMem(Result, Len shl 1); + MultiByteToWideChar(CodePage, 0, PAnsiChar(Text), -1, Result, Len); +end; +{$ENDIF} + +procedure CallTrackMouseEvent(Control: TWinControl; var Status: Boolean); +{$IFDEF USE_WINAPI} +var + TE: TTrackMouseEvent; +begin + if not Status then + begin + TE.cbSize := SizeOf(TE); + TE.dwFlags := TME_LEAVE; + TE.hwndTrack := Control.Handle; + TE.dwHoverTime := HOVER_DEFAULT; + TrackMouseEvent(TE); + Status := True; + end; +end; +{$ELSE} +begin + // This is a TODO for Lazarus team. +end; +{$ENDIF} + +function CharInSetEx(AChar: AnsiChar; const ASet: TKSysCharSet): Boolean; +begin + Result := AChar in ASet; +end; + +function CharInSetEx(AChar: WideChar; const ASet: TKSysCharSet): Boolean; +begin + Result := (Ord(AChar) < $100) and + {$IFDEF COMPILER12_UP} + CharInSet(AChar, ASet); + {$ELSE} + (AnsiChar(AChar) in ASet); + {$ENDIF} +end; + +function CompareIntegers(I1, I2: Integer): Integer; +begin + if I1 > I2 then Result := 1 + else if I1 < I2 then Result := -1 + else Result := 0; +end; + +function CompareWideChars(W1, W2: PWideChar{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal{$ENDIF}): Integer; +begin + if (W1 = nil) or (W2 = nil) then + begin + if W1 <> nil then Result := 1 + else if W2 <> nil then Result := -1 + else Result := 0; + end else + begin + {$IFDEF USE_WIDEWINPROCS} + Result := WideWinProcs.CompareString(Locale, 0, W1, -1, W2, -1); + Dec(Result, 2); + {$ELSE} + Result := WideCompareStr(WideString(W1), WideString(W2)); + {$ENDIF} + end; +end; + +{$IFDEF STRING_IS_UNICODE} +function CompareChars(S1, S2: PChar{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal{$ENDIF}): Integer; +begin + if (S1 = nil) or (S2 = nil) then + begin + if S1 <> nil then Result := 1 + else if S2 <> nil then Result := -1 + else Result := 0; + end else + begin + {$IFDEF USE_WIDEWINPROCS} + Result := WideWinProcs.CompareString(Locale, 0, PWideChar(S1), -1, PWideChar(S2), -1); + Dec(Result, 2); + {$ELSE} + Result := CompareStr(string(S1), string(S2)); + {$ENDIF} + end; +end; +{$ENDIF} + +function CompareWideStrings(W1, W2: WideString{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal{$ENDIF}): Integer; +begin +{$IFDEF USE_WIDEWINPROCS} + Result := WideWinProcs.CompareString(Locale, 0, PWideChar(W1), -1, PWideChar(W2), -1); + Dec(Result, 2); +{$ELSE} + Result := WideCompareStr(W1, W2); +{$ENDIF} +end; + +{$IFDEF STRING_IS_UNICODE} +function CompareStrings(S1, S2: string{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal{$ENDIF}): Integer; +begin +{$IFDEF USE_WIDEWINPROCS} + Result := WideWinProcs.CompareString(Locale, 0, PWideChar(S1), -1, PWideChar(S2), -1); + Dec(Result, 2); +{$ELSE} + Result := CompareStr(S1, S2); +{$ENDIF} +end; +{$ENDIF} + +function DivUp(Dividend, Divisor: Integer): Integer; +begin + if Divisor = 0 then + Result := 0 + else if Dividend mod Divisor > 0 then + Result := Dividend div Divisor + 1 + else + Result := Dividend div Divisor; +end; + +function DivDown(Dividend, Divisor: Integer): Integer; +begin + if Divisor = 0 then + Result := 0 + else if Dividend mod Divisor < 0 then + Result := Dividend div Divisor - 1 + else + Result := Dividend div Divisor; +end; + +procedure Exchange(var Value1, Value2: ShortInt); +var + Tmp: ShortInt; +begin + Tmp := Value1; + Value1 := Value2; + Value2 := Tmp; +end; + +procedure Exchange(var Value1, Value2: SmallInt); +var + Tmp: SmallInt; +begin + Tmp := Value1; + Value1 := Value2; + Value2 := Tmp; +end; + +procedure Exchange(var Value1, Value2: Integer); +var + Tmp: Integer; +begin + Tmp := Value1; + Value1 := Value2; + Value2 := Tmp; +end; + +procedure Exchange(var Value1, Value2: Int64); +var + Tmp: Int64; +begin + Tmp := Value1; + Value1 := Value2; + Value2 := Tmp; +end; + +procedure Exchange(var Value1, Value2: Byte); +var + Tmp: Byte; +begin + Tmp := Value1; + Value1 := Value2; + Value2 := Tmp; +end; + +procedure Exchange(var Value1, Value2: Word); +var + Tmp: Word; +begin + Tmp := Value1; + Value1 := Value2; + Value2 := Tmp; +end; + +procedure Exchange(var Value1, Value2: Cardinal); +var + Tmp: Cardinal; +begin + Tmp := Value1; + Value1 := Value2; + Value2 := Tmp; +end; + +{$IFDEF COMPILER10_UP } +procedure Exchange(var Value1, Value2: UINT64); +var + Tmp: UINT64; +begin + Tmp := Value1; + Value1 := Value2; + Value2 := Tmp; +end; +{$ENDIF} + +procedure Exchange(var Value1, Value2: Single); +var + Tmp: Single; +begin + Tmp := Value1; + Value1 := Value2; + Value2 := Tmp; +end; + +procedure Exchange(var Value1, Value2: Double); +var + Tmp: Double; +begin + Tmp := Value1; + Value1 := Value2; + Value2 := Tmp; +end; + +{$IFNDEF FPC} +procedure Exchange(var Value1, Value2: Extended); +var + Tmp: Extended; +begin + Tmp := Value1; + Value1 := Value2; + Value2 := Tmp; +end; +{$ENDIF} + +procedure Exchange(var Value1, Value2: Char); +var + Tmp: Char; +begin + Tmp := Value1; + Value1 := Value2; + Value2 := Tmp; +end; + +procedure Error(const Msg: string); +begin + raise Exception.Create(Msg); +end; + +function FillMessage(Msg: Cardinal; WParam: WPARAM; LParam: LPARAM): TLMessage; +begin + Result.Msg := Msg; + Result.LParam := LParam; + Result.WParam := WParam; + Result.Result := 0; +end; + +function FormatCurrency(Value: Currency; const AFormat: TKCurrencyFormat): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; +var + OldDecimalSep, OldThousandSep: Char; + Fmt: string; +begin + OldThousandSep := ThousandSeparator; + if AFormat.UseThousandSep then + begin + ThousandSeparator := AFormat.ThousandSep; + Fmt := '%.*n'; + end else + Fmt := '%.*f'; + OldDecimalSep := DecimalSeparator; + DecimalSeparator := AFormat.DecimalSep; + try + case AFormat.CurrencyFormat of + 0: Result := {$IFDEF STRING_IS_UNICODE}Format{$ELSE}WideFormat{$ENDIF}( + '%s' + Fmt, [AFormat.CurrencyString, AFormat.CurrencyDecimals, Value]); + 1: Result := {$IFDEF STRING_IS_UNICODE}Format{$ELSE}WideFormat{$ENDIF}( + Fmt + '%s', [AFormat.CurrencyDecimals, Value, AFormat.CurrencyString]); + 2: Result := {$IFDEF STRING_IS_UNICODE}Format{$ELSE}WideFormat{$ENDIF}( + '%s ' + Fmt, [AFormat.CurrencyString, AFormat.CurrencyDecimals, Value]); + else + Result := {$IFDEF STRING_IS_UNICODE}Format{$ELSE}WideFormat{$ENDIF}( + Fmt + ' %s', [AFormat.CurrencyDecimals, Value, AFormat.CurrencyString]); + end; + finally + DecimalSeparator := OldDecimalSep; + if AFormat.UseThousandSep then + ThousandSeparator := OldThousandSep; + end; +end; + +function GetAppVersion(const ALibName: string; var MajorVersion, MinorVersion, BuildNumber, RevisionNumber: Word): Boolean; +{$IFDEF USE_WINAPI} +var + dwHandle, dwLen: DWORD; + BufLen: Cardinal; + lpData: LPTSTR; + pFileInfo: ^VS_FIXEDFILEINFO; +{$ENDIF} +begin + Result := False; +{$IFDEF USE_WINAPI} + dwLen := GetFileVersionInfoSize(PChar(ALibName), dwHandle); + if dwLen <> 0 then + begin + GetMem(lpData, dwLen); + try + if GetFileVersionInfo(PChar(ALibName), dwHandle, dwLen, lpData) then + begin + if VerQueryValue(lpData, '\\', Pointer(pFileInfo), BufLen) then + begin + MajorVersion := HIWORD(pFileInfo.dwFileVersionMS); + MinorVersion := LOWORD(pFileInfo.dwFileVersionMS); + BuildNumber := HIWORD(pFileInfo.dwFileVersionLS); + RevisionNumber := LOWORD(pFileInfo.dwFileVersionLS); + Result := True; + end; + end; + finally + FreeMem(lpData); + end; + end; +{$ENDIF} +end; + +function GetControlText(Value: TWinControl): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; + + function GetTextBuffer(Value: TWinControl): string; + begin + SetLength(Result, Value.GetTextLen); + Value.GetTextBuf(PChar(Result), Length(Result) + 1); + end; + +begin +{$IFDEF FPC} + Result := GetTextBuffer(Value); // conversion from UTF8 forced anyway +{$ELSE} + {$IFDEF STRING_IS_UNICODE} + Result := GetTextBuffer(Value); + {$ELSE} + if Value.HandleAllocated and (Win32Platform = VER_PLATFORM_WIN32_NT) then // unicode fully supported + begin + SetLength(Result, GetWindowTextLengthW(Value.Handle)); + GetWindowTextW(Value.Handle, PWideChar(Result), Length(Result) + 1); + end else + Result := GetTextBuffer(Value); + {$ENDIF} +{$ENDIF} +end; + +function GetShiftState: TShiftState; +begin + Result := []; + if GetKeyState(VK_SHIFT) < 0 then Include(Result, ssShift); + if GetKeyState(VK_CONTROL) < 0 then Include(Result, ssCtrl); + if GetKeyState(VK_MENU) < 0 then Include(Result, ssAlt); +end; + +function IntToAscii(Value: Int64; Digits: Integer): string; +var + I: Integer; +begin + Result := ''; + I := 0; + while I < Digits do + begin + Result := Result + Chr(Value and $FF); + Value := Value shr 8; + Inc(I); + end; +end; + +function IntToBCD(Value: Cardinal): Cardinal; +var + Exp: Cardinal; +begin + Result := 0; + Exp := 1; + while (Value > 0) and (Exp > 0) do + begin + Result := Result + Value mod 10 * Exp; + Value := Value div 10; + Exp := Exp * 16; + end; +end; + +function IntToBinStr(Value: Int64; Digits: Byte; const Suffix: string): string; +var + B: Byte; + C: Char; +begin + Result := ''; + if Digits <> 0 then + Digits := MinMax(Digits, 1, 64); + repeat + B := Byte(Value and $1); + Value := Value shr 1; + C := Chr(Ord('0') + B); + Result := C + Result; + until (Value = 0) or ((Digits <> 0) and (Length(Result) = Digits)); + while Length(Result) < Digits do + Result := '0' + Result; + Result := Result + Suffix; +end; + +function IntToDecStr(Value: Int64): string; +var + B: Byte; + C: Char; +begin + Result := ''; + repeat + B := Byte(Value mod 10); + Value := Value div 10; + C := Chr(Ord('0') + B); + Result := C + Result; + until Value = 0; +end; + +function IntToHexStr(Value: Int64; Digits: Byte; const Prefix, Suffix: string; UseLowerCase: Boolean): string; +var + B: Byte; + C: Char; +begin + Result := ''; + if Digits <> 0 then + Digits := MinMax(Digits, 1, 16); + repeat + B := Byte(Value and $F); + Value := Value shr 4; + if B < 10 then + C := Chr(Ord('0') + B) else + if UseLowerCase then + C := Chr(Ord('a') + B - 10) + else + C := Chr(Ord('A') + B - 10); + Result := C + Result; + until (Value = 0) or ((Digits <> 0) and (Length(Result) = Digits)); + while Length(Result) < Digits do + Result := '0' + Result; + Result := Prefix + Result + Suffix; +end; + +function IntPowerInt(Value: Int64; Exponent: Integer): Int64; +begin + Result := Value; + while Exponent > 1 do + begin + Result := Result * Value; + Dec(Exponent); + end; +end; + +function AsciiToInt(S: string; Digits: Integer): Int64; +var + I: Integer; +begin + Result := 0; + I := Min(Length(S), Digits); + while I > 0 do + begin + Result := Result shl 8; + Result := Ord(S[I]) + Result; + Dec(I); + end; +end; + +function BCDToInt(Value: Cardinal): Cardinal; +var + Exp: Cardinal; +begin + Result := 0; + Exp := 1; + while Value > 0 do + begin + Result := Result + Min(Value and 15, 9) * Exp; + Value := Value shr 4; + Exp := Exp * 10; + end; +end; + +function BinStrToInt(S: string; Digits: Byte; Signed: Boolean; var Code: Integer): Int64; +var + I, L, Len: Integer; + N: Byte; + C: Char; + M: Int64; +begin + Result := 0; + Code := 0; + L := 0; + Len := Length(S); + if (Digits = 0) or (Digits > 64) then + Digits := 64; + if (Len >= 1) and CharInSetEx(S[Len], ['b', 'B']) then + begin + Delete(S, Len, 1); + Dec(Len); + end; + I := 1; + while I <= Len do + begin + C := S[I]; + N := 255; + if (C >= '0') and (C <= '1') then N := Ord(C) - Ord('0'); + if N > 1 then + begin + Code := I; + Break; + end + else if (N > 0) or (Result <> 0) then + begin + if L >= Digits then + begin + Code := I; + Break; + end; + Result := Result shl 1; + Inc(Result, N); + Inc(L); + end; + Inc(I); + end; + if Signed and (Digits < 64) then + begin + M := Int64(1) shl Digits; + if Result >= M shr 1 - 1 then + Dec(Result, M); + end; +end; + +function DecStrToInt(S: string; var Code: Integer): Int64; +var + I, Len: Integer; + N: Byte; + C: Char; + Minus: Boolean; +begin + Result := 0; + Code := 0; + Len := Length(S); + Minus := S[1] = '-'; + if Minus then I := 2 else I := 1; + while I <= Len do + begin + C := S[I]; + N := 255; + if (C >= '0') and (C <= '9') then N := Ord(C) - Ord('0'); + if N > 9 then + begin + Code := I; + Break; + end + else if (N > 0) or (Result <> 0) then + begin + Result := Result * 10; + Inc(Result, N); + end; + Inc(I); + end; + if Minus then Result := -Result; +end; + +function HexStrToInt(S: string; Digits: Byte; Signed: Boolean; var Code: Integer): Int64; +var + I, L, Len: Integer; + N: Byte; + C: Char; + M: Int64; +begin + Result := 0; + Code := 0; + L := 0; + Len := Length(S); + if (Digits = 0) or (Digits > 16) then + Digits := 16; + if (Len >= 2) and (AnsiChar(S[1]) = '0') and CharInSetEx(S[2], ['x', 'X']) then + I := 3 + else if (Len >= 1) and CharInSetEx(S[1], ['x', 'X', '$']) then + I := 2 + else + I := 1; + while I <= Len do + begin + C := S[I]; + N := 255; + if (C >= '0') and (C <= '9') then N := Ord(C) - Ord('0') + else if (C >= 'a') and (C <= 'f') then N := Ord(C) - Ord('a') + 10 + else if (C >= 'A') and (C <= 'F') then N := Ord(C) - Ord('A') + 10; + if N > 15 then + begin + if CharInSetEx(C, ['h', 'H']) then + begin + if Len > I then Code := I + 1; + end else + Code := I; + Break; + end + else if (N > 0) or (Result <> 0) then + begin + if L >= Digits then + begin + Code := I; + Break; + end; + Result := Result shl 4; + Inc(Result, N); + Inc(L); + end; + Inc(I); + end; + if Signed and (Digits < 16) then + begin + M := Int64(1) shl (Digits shl 2); + if Result >= M shr 1 - 1 then + Dec(Result, M); + end; +end; + +function MinMax(Value, Min, Max: ShortInt): ShortInt; +begin + if Max < Min then + Exchange(Min, Max); + if Value <= Max then + if Value >= Min then + Result := Value + else + Result := Min + else + Result := Max; +end; + +function MinMax(Value, Min, Max: SmallInt): SmallInt; +begin + if Max < Min then + Exchange(Min, Max); + if Value <= Max then + if Value >= Min then + Result := Value + else + Result := Min + else + Result := Max; +end; + +function MinMax(Value, Min, Max: Integer): Integer; +begin + if Max < Min then + Exchange(Min, Max); + if Value <= Max then + if Value >= Min then + Result := Value + else + Result := Min + else + Result := Max; +end; + +function MinMax(Value, Min, Max: Int64): Int64; +begin + if Max < Min then + Exchange(Min, Max); + if Value <= Max then + if Value >= Min then + Result := Value + else + Result := Min + else + Result := Max; +end; + +function MinMax(Value, Min, Max: Single): Single; +begin + if Max < Min then + Exchange(Min, Max); + if Value <= Max then + if Value >= Min then + Result := Value + else + Result := Min + else + Result := Max; +end; + +function MinMax(Value, Min, Max: Double): Double; +begin + if Max < Min then + Exchange(Min, Max); + if Value <= Max then + if Value >= Min then + Result := Value + else + Result := Min + else + Result := Max; +end; + +{$IFNDEF FPC} +function MinMax(Value, Min, Max: Extended): Extended; +begin + if Max < Min then + Exchange(Min, Max); + if Value <= Max then + if Value >= Min then + Result := Value + else + Result := Min + else + Result := Max; +end; +{$ENDIF} + +procedure SetControlClipRect(AControl: TWinControl; const ARect: TRect); +begin + if AControl.HandleAllocated then + begin + {$IFDEF USE_WINAPI} + SetWindowRgn(AControl.Handle, CreateRectRgn(0, 0, ARect.Right - ARect.Left, ARect.Bottom - ARect.Top), True); + {$ELSE} + //how to do that? + {$ENDIF} + end; +end; + +procedure SetControlText(Value: TWinControl; const Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); + + procedure SetTextBuffer(Value: TWinControl; const Text: string); + begin + Value.SetTextBuf(PChar(Text)); + end; + +begin +{$IFDEF FPC} + SetTextBuffer(Value, Text); // conversion to UTF8 forced anyway +{$ELSE} + {$IFDEF STRING_IS_UNICODE} + SetTextBuffer(Value, Text); + {$ELSE} + if Value.HandleAllocated and (Win32Platform = VER_PLATFORM_WIN32_NT) then // unicode fully supported + SetWindowTextW(Value.Handle, PWideChar(Text)) + else + SetTextBuffer(Value, Text); + {$ENDIF} +{$ENDIF} +end; + +function StrNextCharIndex(AText: {$IFDEF STRING_IS_UNICODE}PChar{$ELSE}PWideChar{$ENDIF}; Index: Integer): Integer; +begin +{$IFDEF FPC} + Result := Index + UTF8CharacterLength(@AText[Index]); +{$ELSE} + Result := Index + 1; // neglecting surrogate pairs +{$ENDIF} +end; + +function StringCharBegin(const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; Index: Integer): Integer; +begin +{$IFDEF FPC} + Result := UTF8CharToByteIndex(PChar(AText), Length(AText), Index) +{$ELSE} + Result := Index // neglecting surrogate pairs +{$ENDIF} +end; + +function StringLength(const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}): Integer; +begin +{$IFDEF FPC} + Result := UTF8Length(AText) +{$ELSE} + Result := Length(AText) // neglecting surrogate pairs +{$ENDIF} +end; + +function StringNextCharIndex(const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; Index: Integer): Integer; +begin +{$IFDEF FPC} + Result := Index + UTF8CharacterLength(@AText[Index]); +{$ELSE} + Result := Index + 1; // neglecting surrogate pairs +{$ENDIF} +end; + +procedure TrimWhiteSpaces(var AText: {$IFDEF STRING_IS_UNICODE}PChar{$ELSE}PWideChar{$ENDIF}; var ALen: Integer; const ASet: TKSysCharSet); +begin + while (ALen > 0) and CharInSetEx(AText[0], ASet) do + begin + AText := @AText[1]; + Dec(ALen) + end; + while (ALen > 0) and CharInSetEx(AText[ALen - 1], ASet) do + Dec(ALen); +end; + +procedure TrimWhiteSpaces(var AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; const ASet: TKSysCharSet); +begin + while (Length(AText) > 0) and CharInSetEx(AText[1], ASet) do + Delete(AText, 1, 1); + while (Length(AText) > 0) and CharInSetEx(AText[Length(AText)], ASet) do + Delete(AText, Length(AText), 1); +end; + +{$IFNDEF FPC} +function WideCharToAnsiString(Text: PWideChar; CodePage: Cardinal): AnsiString; +var + Len: Integer; +begin + Len := WideCharToMultiByte(CodePage, 0, Text, -1, nil, 0, nil, nil); + SetLength(Result, Len); + WideCharToMultiByte(CodePage, 0, Text, -1, PAnsiChar(Result), Len, nil, nil); +end; +{$ENDIF} + +{$IFDEF USE_WINAPI} +function GetWindowsFolder(CSIDL: Cardinal; var APath: string): Boolean; +type + TSHGetFolderPathProc = function(hWnd: HWND; CSIDL: Integer; hToken: THandle; + dwFlags: DWORD; pszPath: PAnsiChar): HResult; stdcall; +var + SHFolderHandle: HMODULE; + SHGetFolderPathProc: TSHGetFolderPathProc; + Buffer: PAnsiChar; +begin + Result := False; + APath := ''; + SHFolderHandle := GetModuleHandle(SHFolderDll); + if SHFolderHandle <> 0 then + begin + SHGetFolderPathProc := GetProcAddress(SHFolderHandle, 'SHGetFolderPathA'); + if Assigned(SHGetFolderPathProc) then + begin + GetMem(Buffer, MAX_PATH); + try + if Succeeded(SHGetFolderPathProc(0, CSIDL, 0, 0, Buffer)) then + begin + APath := string(Buffer); + Result := True; + end + finally + FreeMem(Buffer); + end; + end; + end; +end; +{$ENDIF} + +end. diff --git a/components/kcontrols/source/kgraphics.pas b/components/kcontrols/source/kgraphics.pas new file mode 100755 index 000000000..a34402e3f --- /dev/null +++ b/components/kcontrols/source/kgraphics.pas @@ -0,0 +1,2145 @@ +{ @abstract(This unit contains advanced graphic functions used by KControls suite.) + @author(Tomas Krysl (tk@tkweb.eu)) + @created(5 May 2004) + @lastmod(20 Jun 2010) + + Copyright © 2004 Tomas Krysl (tk@@tkweb.eu)

+ + License:
+ This code is distributed as a freeware. You are free to use it as part + of your application for any purpose including freeware, commercial and + shareware applications. The origin of this source code must not be + misrepresented; you must not claim your authorship. You may modify this code + solely for your own purpose. Please feel free to contact the author if you + think your changes might be useful for other users. You may distribute only + the original package. The author accepts no liability for any damage + that may result from using this code. } + +unit KGraphics; + +{$include kcontrols.inc} +{$WEAKPACKAGEUNIT ON} + +interface + +uses +{$IFDEF FPC} + // use the LCL interface support whenever possible + {$IFDEF USE_WINAPI} + Windows, + {$ENDIF} + GraphType, IntfGraphics, LCLType, LCLIntf, LMessages, LResources, +{$ELSE} + Windows, Messages, + {$IFDEF USE_PNG_SUPPORT} + PngImage, + {$ENDIF} +{$ENDIF} + Classes, Forms, Graphics, Controls, KFunctions; + +resourcestring + { @exclude } + SGDIError = 'GDI object could not be created.'; + +const + { PNG Support } + PNGHeader = #137'PNG'#13#10#26#10; + MNGHeader = #138'MNG'#13#10#26#10; + +type + { Declares possible values for the Style parameter of the @link(BrightColor) function. } + TKBrightMode = ( + { The Color will be brightened with Percent of its entire luminosity range. } + bsAbsolute, + { The Color will be brightened with Percent of its current luminosity value. } + bsOfBottom, + { The Color will be brightened with Percent of the difference of its entire + luminosity range and current luminosity value. } + bsOfTop + ); + + { Declares RGB + Alpha channel color description allowing both to + access single channels and the whole color item. } + TKColorRec = packed record + case Integer of + 0: (R, G, B, A: Byte); + 1: (Value: Cardinal); + end; + + { Pointer to TKColorRec. } + PKColorRec = ^TKColorRec; + + { Dynamic array for TKColorRec. } + TKColorRecs = array[0..MaxInt div SizeOf(TKColorRec) - 1] of TKColorRec; + { Dynamic array for TKColorRecs. } + PKColorRecs = ^TKColorRecs; + { Dynamic array for TKColorRec. } + TKDynColorRecs = array of TKColorRec; + + { String type for @link(ImageByType) function. } + TKImageHeaderString = string[10]; + +{$IFDEF USE_PNG_SUPPORT} + {$IFDEF FPC} + { @exclude } + TKPngImage = TPortableNetworkGraphic; + {$ELSE} + {$IFDEF COMPILER12_UP} + { @exclude } + TKPngImage = TPngImage; + {$ELSE} + { @exclude } + TKPngImage = TPngObject; + {$ENDIF} + {$ENDIF} +{$ENDIF} + + { Declares possible values for the Attributes parameter in the @link(DrawAlignedText) function. } + TKTextAttribute = ( + { Bounding rectangle is calculated. No text is drawn. } + taCalcRect, + { Text will be clipped within the given rectangle. } + taClip, + { Text will be drawn with end ellipsis if it does not fit within given width. } + taEndEllipsis, + { Given rectangle will be filled. } + taFillRect, + { Only yhe text within given rectangle will be filled. } + taFillText, + { Text will be drawn as multi-line text if it contains carriage returns and line feeds. } + taLineBreak, + { Text will be drawn with path ellipsis if it does not fit within given width. } + taPathEllipsis, + { Text line(s) will be broken between words if they don't fit within given width. } + taWordBreak, + { Text line(s) will be broken if they don't fit within col width. } + taWrapText, //JR:20091229 + { No white spaces will be trimmed at the beginning or end of text lines. } + taTrimWhiteSpaces + ); + + { Set type for @link(TKTextAttribute) enumeration. } + TKTextAttributes = set of TKTextAttribute; + + { Declares possible values for the HAlign parameter in the @link(DrawAlignedText) function. } + TKHAlign = ( + { Text is aligned to the left border of a cell rectangle. } + halLeft, + { Text is horizontally centered within the cell rectangle. } + halCenter, + { Text is aligned to the right border of a cell rectangle. } + halRight + ); + + { Declares possible values for the StretchMode parameter in the @link(ExcludeShapeFromBaseRect) function. } + TKStretchMode = ( + { Shape is not stretched. } + stmNone, + { Shape is zoomed out. } + stmZoomOutOnly, + { Shape is zoomed in. } + stmZoomInOnly, + { Shape is zoomed arbitrary. } + stmZoom + ); + + { For backward compatibility. } + TKTextHAlign = TKHAlign; + + { Declares possible values for the VAlign parameter in the @link(DrawAlignedText) function. } + TKVAlign = ( + { Text is aligned to the upper border of a cell rectangle. } + valTop, + { Text is vertically centered within the cell rectangle. } + valCenter, + { Text is aligned to the lower border of a cell rectangle. } + valBottom + ); + + { For backward compatibility. } + TKTextVAlign = TKVAlign; + + { A simple platform independent encapsulation for a 32bpp bitmap with + alpha channel with the ability to modify it's pixels directly. } + TKAlphaBitmap = class(TGraphic) + private + FCanvas: TCanvas; + FDirectCopy: Boolean; + FHandle: HBITMAP; + FHeight: Integer; + {$IFNDEF USE_WINAPI} + FImage: TLazIntfImage; // Lazarus only + FMaskHandle: HBITMAP; + {$ENDIF} + FOldBitmap: HBITMAP; + FPixels: PKColorRecs; + FPixelsChanged: Boolean; + FWidth: Integer; + function GetScanLine(Index: Integer): PKColorRecs; + function GetHandle: HBITMAP; + function GetPixel(X, Y: Integer): TKColorRec; + procedure SetPixel(X, Y: Integer; Value: TKColorRec); + protected + { Paints itself to ACanvas at location ARect. } + procedure Draw(ACanvas: TCanvas; const ARect: TRect); override; + { Returns True if bitmap is empty. } + function GetEmpty: Boolean; override; + { Returns the bitmap height. } + function GetHeight: Integer; override; + { Returns True. Treat alpha bitmap as transparent because of the + possible alpha channel. } + function GetTransparent: Boolean; override; + { Returns the bitmap width. } + function GetWidth: Integer; override; + { Specifies new bitmap height. } + procedure SetHeight(Value: Integer); override; + { Specifies new bitmap width. } + procedure SetWidth(Value: Integer); override; + { Does nothing. Bitmap is never transparent. } + procedure SetTransparent(Value: Boolean); override; + { Updates the bitmap handle from bitmap pixels. } + procedure UpdateHandle; dynamic; + { Updates the pixels from bitmap handle. } + procedure UpdatePixels; dynamic; + public + { Creates the instance. } + constructor Create; override; + { Creates the instance from application resources. For Lazarus 'BMP' type is + taken, for Delphi RT_RCDATA is taken. } + constructor CreateFromRes(const ResName: string); + { Destroys the instance. } + destructor Destroy; override; + { Paints alpha bitmap onto Canvas at position given by X, Y. The alpha bitmap + is combined with the background already drawn on Canvas using alpha channel + stored in the alpha bitmap. } + procedure AlphaDrawTo(ACanvas: TCanvas; X, Y: Integer); + { Paints alpha bitmap onto Canvas at position given by ARect. The alpha bitmap + is combined with the background already drawn on Canvas using alpha channel + stored in the alpha bitmap. } + procedure AlphaStretchDrawTo(ACanvas: TCanvas; const ARect: TRect); + { Fills the alpha channel with Alpha. If the optional IfEmpty parameter is True, + the alpha channel won't be modified unless it has zero value for all pixels. } + procedure AlphaFill(Alpha: Byte; IfEmpty: Boolean = False); overload; + { Fills the alpha channel according to given parameters. Currently it is used + internally by @link(TKDragWindow). } + procedure AlphaFill(Alpha: Byte; BlendColor: TColor; Gradient, Translucent: Boolean); overload; + { Combines the pixel at given location with the given color. } + procedure CombinePixel(X, Y: Integer; Color: TKColorRec); + { Takes dimensions and pixels from ABitmap. } + procedure CopyFrom(ABitmap: TKAlphaBitmap); + { Takes 90°-rotated dimensions and pixels from ABitmap. } + procedure CopyFromRotated(ABitmap: TKAlphaBitmap); + { Copies a location specified by ARect from ACanvas to bitmap. } + procedure DrawFrom(ACanvas: TCanvas; const ARect: TRect); + { Calls @link(TKAlphaBitmap.Draw). } + procedure DrawTo(ACanvas: TCanvas; const ARect: TRect); + {$IFNDEF FPC} + { Does nothing. } + procedure LoadFromClipboardFormat(AFormat: Word; AData: THandle; + APalette: HPALETTE); override; + {$ENDIF} + { Loads the bitmap from a stream. } + procedure LoadFromStream(Stream: TStream); override; + { Mirrors the bitmap pixels horizontally. } + procedure MirrorHorz; + { Mirrors the bitmap pixels vertically. } + procedure MirrorVert; + {$IFNDEF FPC} + { Does nothing. } + procedure SaveToClipboardFormat(var AFormat: Word; var AData: THandle; + var APalette: HPALETTE); override; + {$ENDIF} + { Saves the bitmap to a stream. } + procedure SaveToStream(Stream: TStream); override; + { Specifies the bitmap size. } + procedure SetSize(AWidth, AHeight: Integer); {$IFNDEF FPC} reintroduce;{$ENDIF} + { Returns the bitmap memory canvas. } + property Canvas: TCanvas read FCanvas; + { Temporary flag. Use when copying data directly from another TGraphic to TKAlphaBitmap. } + property DirectCopy: Boolean read FDirectCopy write FDirectCopy; + { Returns the bitmap handle. } + property Handle: HBITMAP read GetHandle; + { Specifies the pixel color. Does range checking. } + property Pixel[X, Y: Integer]: TKColorRec read GetPixel write SetPixel; + { Returns the pointer to bitmap pixels. } + property Pixels: PKColorRecs read FPixels; + { Set this property to True if you have modified the bitmap pixels. } + property PixelsChanged: Boolean read FPixelsChanged write FPixelsChanged; + { Returns the pointer to a bitmap scan line. } + property ScanLine[Index: Integer]: PKColorRecs read GetScanLine; + end; + +{$IFDEF USE_WINAPI} + TUpdateLayeredWindowProc = function(Handle: THandle; hdcDest: HDC; pptDst: PPoint; + _psize: PSize; hdcSrc: HDC; pptSrc: PPoint; crKey: COLORREF; pblend: PBLENDFUNCTION; + dwFlags: DWORD): Boolean; stdcall; +{$ENDIF} + + { @abstract(Encapsulates the drag window) + Drag window is top level window used for dragging with mouse. It displays + some portion of associated control. It can be translucent under Windows. } + TKDragWindow = class(TObject) + private + FActive: Boolean; + FAlphaEffects: Boolean; + FBitmap: TKAlphaBitmap; + FBitmapFilled: Boolean; + FControl: TCustomControl; + FGradient: Boolean; + FInitialPos: TPoint; + FLayered: Boolean; + FMasterAlpha: Byte; + {$IFDEF USE_WINAPI} + FBlend: TBlendFunction; + FUpdateLayeredWindow: TUpdateLayeredWindowProc; + FWindow: HWND; + {$ELSE} + FDragForm: TCustomForm; + {$ENDIF} + public + { Creates the instance. } + constructor Create; + { Destroys the instance. } + destructor Destroy; override; + { Shows the drag window on screen. Takes a rectangular part as set by ARect from + IniCtrl's Canvas and displays it at position InitialPos. MasterAlpha and + Gradient are used to premaster the copied image with a specific fading effect. } + procedure Show(IniCtrl: TCustomControl; const ARect: TRect; const InitialPos, + CurrentPos: TPoint; MasterAlpha: Byte; Gradient: Boolean); + { Moves the drag window to a new location. } + procedure Move(const NewPos: TPoint); + { Hides the drag window. } + procedure Hide; + { Returns True if the drag window is shown. } + property Active: Boolean read FActive; + { Returns the pointer to the bitmap that holds the copied control image. } + property Bitmap: TKAlphaBitmap read FBitmap; + { Returns True if the control already copied itself to the bitmap. } + property BitmapFilled: Boolean read FBitmapFilled; + end; + + { @abstract(Base class for KControls hints) + This class extends the standard THintWindow class. It adds functionality + common to all hints used in KControls. } + TKHintWindow = class(THintWindow) + private + FExtent: TPoint; + procedure WMEraseBkGnd(var Msg: TLMessage); message LM_ERASEBKGND; + public + { Creates the instance. } + constructor Create(AOwner: TComponent); override; + { Shows the hint at given position. This is an IDE independent implementation. } + procedure ShowAt(const Origin: TPoint); + { Returns the extent of the hint. } + property Extent: TPoint read FExtent; + end; + + { @abstract(Hint window to display formatted text) + This class implements the textual hint window. The text is displayed . } + TKTextHint = class(TKHintWindow) + private + FText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; + procedure SetText(const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); + protected + { Overriden method. Paints the hint. } + procedure Paint; override; + public + { Creates the instance. } + constructor Create(AOwner: TComponent); override; + { } + property Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF} read FText write SetText; + end; + + TKGraphicHint = class(TKHintWindow) + private + FGraphic: TGraphic; + procedure SetGraphic(const Value: TGraphic); + protected + { Overriden method. Paints the hint. } + procedure Paint; override; + public + constructor Create(AOwner: TComponent); override; + property Graphic: TGraphic read FGraphic write SetGraphic; + end; + +{ Draws Src to Dest with per pixel weighting by alpha channel saved in Src. } +procedure BlendLine(Src, Dest: PKColorRecs; Count: Integer); + +{ Calculates a brighter color of given color based on the HSL color space. +
    + Parameters: +
  • Color - input color.
  • +
  • Percent - percentage of luminosity to bright the color (0 to 1).
  • +
  • Mode - identifies how the Percent parameter should be interpreted.
  • +
} +function BrightColor(Color: TColor; Percent: Single; Mode: TKBrightMode = bsAbsolute): TColor; + +{ Returns current canvas window/wiewport scaling. } +procedure CanvasGetScale(ACanvas: TCanvas; out MulX, MulY, DivX, DivY: Integer); + +{ Selects the default window/wiewport scaling to given canvas for both axes. } +procedure CanvasResetScale(ACanvas: TCanvas); + +{ Returns True if the ACanvas's device context has been mapped to anything else + than MM_TEXT. } +function CanvasScaled(ACanvas: TCanvas): Boolean; + +{ Selects the window/wiewport scaling to given canvas for both axes. } +procedure CanvasSetScale(ACanvas: TCanvas; MulX, MulY, DivX, DivY: Integer); + +{ Selects the wiewport offset to given canvas for both axes. } +procedure CanvasSetOffset(ACanvas: TCanvas; OfsX, OfsY: Integer); + +{ Makes a grayscale representation of the given color. } +function ColorToGrayScale(Color: TColor): TColor; + +{ Calls BitBlt. } +procedure CopyBitmap(DestDC: HDC; DestRect: TRect; SrcDC: HDC; SrcX, SrcY: Integer); + +{ Creates an empty rectangular region. } +function CreateEmptyRgn: HRGN; + +{ Draws Text to the Canvas at location given by ARect. + HAlign and VAlign specify horizontal resp. vertical alignment of the text + within ARect. HPadding and VPadding specify horizontal (both on left and right side) + and vertical (both on top and bottom side) padding of the Text from ARect. + BackColor specifies the fill color for brush gaps if a non solid Brush + is defined in Canvas. Attributes specift various text output attributes. } +procedure DrawAlignedText(Canvas: TCanvas; var ARect: TRect; + HAlign: TKHAlign; VAlign: TKVAlign; HPadding, VPadding: Integer; + const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; + BackColor: TColor = clWhite; Attributes: TKTextAttributes = []); + +{ Simulates WinAPI DrawEdge with customizable colors. } +procedure DrawEdges(Canvas: TCanvas; const R: TRect; HighlightColor, + ShadowColor: TColor; Flags: Cardinal); + +{ Draws a rectangle to Canvas. The rectangle coordinates are given by Rect. + The rectangle is filled by Brush. If Brush is not solid, its gaps are filled + with BackColor. If BackColor is clNone these gaps are not filled and the Brush + appears transparent. } +procedure DrawFilledRectangle(Canvas: TCanvas; const ARect: TRect; + BackColor: TColor); + +{ This helper function excludes a rectangular area occupied by a shape from + BaseRect and calculates the shape area rectangles Bounds and Interior. + The shape area is specified by the shape extent (ShapeWidth and ShapeHeight), + padding (HPadding and VPadding) and stretching mode (StretchMode). + The returned Bounds includes (possibly stretched) shape + padding, + and Interior includes only the (possibly stretched) shape. + HAlign specifies the horizontal alignment of shape area within BaseRect. + VAlign specifies the vertical alignment of shape area within BaseRect. + The shape area is always excluded horizontally from BaseRect, as needed by cell + data calculations in KGrid. } +procedure ExcludeShapeFromBaseRect(var BaseRect: TRect; ShapeWidth, ShapeHeight: Integer; + HAlign: TKHAlign; VAlign: TKVAlign; HPadding, VPadding: Integer; + StretchMode: TKStretchMode; out Bounds, Interior: TRect); + +{ Selects ARect into device context. Returns previous clipping region. } +function ExtSelectClipRect(DC: HDC; ARect: TRect; Mode: Integer; out PrevRgn: HRGN): Boolean; + +{ Selects ARect into device context. Combines with CurRgn and + returns previous clipping region. Both regions have to be created first. } +function ExtSelectClipRectEx(DC: HDC; ARect: TRect; Mode: Integer; CurRgn, PrevRgn: HRGN): Boolean; + +{ Fills the area specified by the difference Boundary - Interior on ACanvas with current Brush. + If Brush is not solid, its gaps are filled with BackColor. If BackColor is + clNone these gaps are not filled and the Brush appears transparent. } +procedure FillAroundRect(ACanvas: TCanvas; const Boundary, Interior: TRect; BackColor: TColor); + +{ Selects the region into given device context and deletes the region. } +procedure FinalizePrevRgn(DC: HDC; ARgn: HRGN); + +{ Determine the height (ascent + descent) of the font currently selected into given DC. } +function GetFontHeight(DC: HDC): Integer; + +{ Raises an exception if GDI resource has not been created. } +function GDICheck(Value: Integer): Integer; + +{ Creates a TGraphic instance according to the image file header. + Currently supported images are BMP, PNG, MNG, JPG, ICO. } +function ImageByType(const Header: TKImageHeaderString): TGraphic; + +{ Calls the IntersectClipRect function. } +function IntersectClipRectIndirect(DC: HDC; ARect: TRect): Boolean; + +{ Determines if given color has lightness > 0.5. } +function IsBrightColor(Color: TColor): Boolean; + +{ Loads a custom mouse cursor. } +procedure LoadCustomCursor(Cursor: TCursor; const ResName: string); + +{ Builds a TKColorRec structure. } +function MakeColorRec(R, G, B, A: Byte): TKColorRec; + +{ Returns a pixel format that matches Bpp. } +function PixelFormatFromBpp(Bpp: Cardinal): TPixelFormat; + +{ In Lazarus this WinAPI function is missing. } +function RectInRegion(Rgn: HRGN; ARect: TRect): Boolean; + +{ Paints an image so that it fits in ARect. Performs double buffering and fills + the background with current brush for mapped device contexts. } +procedure SafeStretchDraw(ACanvas: TCanvas; ARect: TRect; AGraphic: TGraphic; ABackColor: TColor = clWhite); + +{ Selects ARect as new clipping region into the device context. } +procedure SelectClipRect(DC: HDC; const ARect: TRect); + +{ Calls StretchBlt. } +procedure StretchBitmap(DestDC: HDC; DestRect: TRect; SrcDC: HDC; SrcRect: TRect); + +{ Swaps the color format from RGB to BGR and vice versa. } +function SwitchRGBToBGR(Value: TColor): TColor; + +{ Subtracts the current device context offset to ARect. } +procedure TranslateRectToDevice(DC: HDC; var ARect: TRect); + +implementation + +uses + Math, SysUtils, Types, KControls +{$IFDEF FPC} + , FPImage +{$ELSE} + , JPeg +{$ENDIF} + ; + +procedure BlendLine(Src, Dest: PKColorRecs; Count: Integer); +var + I: Integer; + R, G, B, A1, A2: Integer; +begin + // without assembler + for I := 0 to Count - 1 do + begin + A1 := Src[I].A; + A2 := 255 - A1; + Inc(A1); + Inc(A2); + R := Src[I].R * A1 + Dest[I].R * A2; + G := Src[I].G * A1 + Dest[I].G * A2; + B := Src[I].B * A1 + Dest[I].B * A2; + Dest[I].R := R shr 8; + Dest[I].G := G shr 8; + Dest[I].B := B shr 8; + end; +end; + +function CalcLightness(Color: TColor): Single; +var + X: TKColorRec; +begin + X.Value := ColorToRGB(Color); + Result := (X.R + X.G + X.B) / (3 * 256); +end; + +function BrightColor(Color: TColor; Percent: Single; Mode: TKBrightMode): TColor; +var + L, Tmp: Single; + + function Func1(Value: Single): Single; + begin + Result := Value * (L + Percent) / L; + end; + + function Func2(Value: Single): Single; + begin + Result := 1 - (0.5 - Tmp) * (1 - Value) / (1 - L); + { this is the shorter form of + Value := 1 - 0.5 * (1 - Value) / (1 - L) ; // get color with L = 0.5 + Result := 1 - (0.5 - Tmp) * (1 - Value) / 0.5; // get corresponding color + } + end; + + function Rd(Value: Single): Byte; + begin + Result := Min(Integer(Round(Value * 255)), 512); + end; + +var + R, G, B, Cmax, Cmin: Single; + X: TKColorRec; +begin + X.Value := ColorToRGB(Color); + R := X.R / 255; + G := X.G / 255; + B := X.B / 255; + Cmax := Max(R, Max(G, B)); + Cmin := Min(R, Min(G, B)); + L := (Cmax + Cmin) / 2; + if L < 1 then + begin + case Mode of + bsOfBottom: Percent := L * Percent; + bsOfTop: Percent := (1 - L) * Percent; + end; + Percent := Min(Percent, 1 - L); + if L = 0 then + begin + // zero length singularity + R := R + Percent; G := G + Percent; B := B + Percent; + end else + begin + Tmp := L + Percent - 0.5; + // lumination below 0.5 + if L < 0.5 then + begin + // if L + Percent is >= 0.5, get color with L = 0.5 + Percent := Min(Percent, 0.5 - L); + R := Func1(R); G := Func1(G); B := Func1(B); + L := 0.5; + end; + // lumination above 0.5 + if Tmp > 0 then + begin + R := Func2(R); G := Func2(G); B := Func2(B); + end; + end; + X.R := Rd(R); + X.G := Rd(G); + X.B := Rd(B); + end; + Result := X.Value; +end; + +procedure CanvasGetScale(ACanvas: TCanvas; out MulX, MulY, DivX, DivY: Integer); +{$IFDEF USE_DC_MAPPING} +var + WindowExt, ViewPortExt: TSize; +{$ENDIF} +begin +{$IFDEF USE_DC_MAPPING} + if Boolean(GetWindowExtEx(ACanvas.Handle, {$IFDEF FPC}@{$ENDIF}WindowExt)) and + Boolean(GetViewPortExtEx(ACanvas.Handle, {$IFDEF FPC}@{$ENDIF}ViewPortExt)) then + begin + DivX := WindowExt.cx; DivY := WindowExt.cy; + MulX := ViewPortExt.cx; MulY := ViewPortExt.cy; + end else +{$ENDIF} + begin + MulX := 1; DivX := 1; + MulY := 1; DivY := 1; + end; +end; + +procedure CanvasResetScale(ACanvas: TCanvas); +begin +{$IFDEF USE_DC_MAPPING} + SetMapMode(ACanvas.Handle, MM_TEXT); +{$ENDIF} +end; + +function CanvasScaled(ACanvas: TCanvas): Boolean; +begin +{$IFDEF USE_DC_MAPPING} + Result := not (GetMapMode(ACanvas.Handle) in [0, MM_TEXT]); +{$ELSE} + Result := False; +{$ENDIF} +end; + +procedure CanvasSetScale(ACanvas: TCanvas; MulX, MulY, DivX, DivY: Integer); +begin +{$IFDEF USE_DC_MAPPING} + SetMapMode(ACanvas.Handle, MM_ANISOTROPIC); + SetWindowExtEx(ACanvas.Handle, DivX, DivY, nil); + SetViewPortExtEx(ACanvas.Handle, MulX, MulY, nil); +{$ELSE} + {$WARNING 'Device context window/viewport transformations not working!'} +{$ENDIF} +end; + +procedure CanvasSetOffset(ACanvas: TCanvas; OfsX, OfsY: Integer); +begin +{$IFDEF USE_DC_MAPPING} + SetMapMode(ACanvas.Handle, MM_ANISOTROPIC); + SetViewPortOrgEx(ACanvas.Handle, OfsX, OfsY, nil); +{$ENDIF} +end; + +function ColorToGrayScale(Color: TColor): TColor; +var + GreyValue: Integer; + X: TKColorRec; +begin + X.Value := ColorToRGB(Color); + GreyValue := (X.R + X.G + X.B) div 3; + X.R := GreyValue; + X.G := GreyValue; + X.B := GreyValue; + Result := X.Value; +end; + +procedure CopyBitmap(DestDC: HDC; DestRect: TRect; SrcDC: HDC; SrcX, SrcY: Integer); +begin + {$IFDEF USE_WINAPI}Windows.{$ENDIF}BitBlt(DestDC, + DestRect.Left, DestRect.Top, DestRect.Right - DestRect.Left, DestRect.Bottom - DestRect.Top, + SrcDC, 0, 0, SRCCOPY); +end; + +function CreateEmptyRgn: HRGN; +begin + Result := CreateRectRgn(0,0,0,0); +end; + +procedure DrawAlignedText(Canvas: TCanvas; var ARect: TRect; + HAlign: TKHAlign; VAlign: TKVAlign; HPadding, VPadding: Integer; + const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; + BackColor: TColor; Attributes: TKTextAttributes); +var + DC: HDC; + FontHeight: Integer; + ClipRect: TRect; + + function MeasureOrOutput(Y: Integer; Output: Boolean): TSize; + var + EndEllipsis, PathEllipsis: Boolean; + Width, EllipsisWidth: Integer; + + function TextExtent(AText: {$IFDEF STRING_IS_UNICODE}PChar{$ELSE}PWideChar{$ENDIF}; ALen: Integer; Trim: Boolean = False): TSize; + begin + if Trim then + begin + if taLineBreak in Attributes then + TrimWhiteSpaces(AText, ALen, cLineBreaks); + if taTrimWhiteSpaces in Attributes then + TrimWhiteSpaces(AText, ALen, cWordBreaks); + end; + {$IFDEF STRING_IS_UNICODE} + {$IFDEF FPC} + {$IFDEF USE_CANVAS_METHODS} + Result := Canvas.TextExtent(Copy(AText, 0, ALen)); // little slower but more secure in Lazarus + {$ELSE} + GetTextExtentPoint32(DC, AText, ALen, Result); + {$ENDIF} + {$ELSE} + GetTextExtentPoint32(DC, AText, ALen, Result); + {$ENDIF} + {$ELSE} + GetTextExtentPoint32W(DC, AText, ALen, Result); + {$ENDIF} + end; + + procedure FmtTextOut(Y: Integer; AText: {$IFDEF STRING_IS_UNICODE}PChar{$ELSE}PWideChar{$ENDIF}; ALen: Integer); + var + DrawEllipsis, DrawFileName: Boolean; + AWidth, Index, NewIndex,SlashPos, FileNameLen, EllipsisMaxX, X: Integer; + S: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; + begin + DrawEllipsis := False; + DrawFileName := False; + SlashPos := 0; + FileNameLen := 0; + if taLineBreak in Attributes then + TrimWhiteSpaces(AText, ALen, cLineBreaks); + if taTrimWhiteSpaces in Attributes then + TrimWhiteSpaces(AText, ALen, cWordBreaks); + if (EndEllipsis or PathEllipsis) and (ALen > 1) then + begin + AWidth := TextExtent(AText, ALen).cx; + if AWidth > Width then + begin + AWidth := 0; + Index := 0; + if EndEllipsis then + begin + EllipsisMaxX := Width - EllipsisWidth; + while (Index < ALen) do + begin + NewIndex := StrNextCharIndex(AText, Index); + Inc(AWidth, TextExtent(@AText[Index], NewIndex - Index).cx); + if (AWidth > EllipsisMaxX) and (Index > 0) then + Break + else + Index := NewIndex; + end; + ALen := Index; + DrawEllipsis := True; + end + else if PathEllipsis then + begin + SlashPos := ALen; + while (SlashPos > 0) and not CharInSetEx(AText[SlashPos], ['/', '\']) do + Dec(SlashPos); + if SlashPos > 0 then + begin + DrawEllipsis := True; + DrawFileName := True; + FileNameLen := ALen - SlashPos; + EllipsisMaxX := Width - TextExtent(@AText[SlashPos], FileNameLen).cx - EllipsisWidth; + while (Index < SlashPos) do + begin + NewIndex := StrNextCharIndex(AText, Index); + Inc(AWidth, TextExtent(@AText[Index], NewIndex - Index).cx); + if AWidth > EllipsisMaxX then + Break + else + Index := NewIndex; + end; + ALen := Index; + end; + end; + end; + end; + if DrawEllipsis then + begin + if DrawFileName then + begin + S := Copy(AText, 0, ALen) + cEllipsis + Copy(AText, SlashPos + 1, FileNameLen); + end else + S := Copy(AText, 0, ALen) + cEllipsis; + AText := {$IFDEF STRING_IS_UNICODE}PChar{$ELSE}PWideChar{$ENDIF}(S); + ALen := Length(S); + end; + case HAlign of + halCenter: + X := Max(ClipRect.Left, (ClipRect.Left + ClipRect.Right - TextExtent(AText, ALen).cx) div 2); + halRight: + X := ClipRect.Right - TextExtent(AText, ALen).cx; + else + X := ClipRect.Left; + end; + {$IFDEF STRING_IS_UNICODE} + {$IFDEF FPC} + {$IFDEF USE_CANVAS_METHODS} + Canvas.TextOut(X, Y, Copy(AText, 0, ALen)); // little slower but more secure in Lazarus + {$ELSE} + TextOut(DC, X, Y, AText, ALen); + {$ENDIF} + {$ELSE} + TextOut(DC, X, Y, AText, ALen); + {$ENDIF} + {$ELSE} + TextOutW(DC, X, Y, AText, ALen); + {$ENDIF} + end; + + var + I, Index, TextLen, LineBegin, LineBreaks, Vert: Integer; + CalcRect, WordBreak, LineBreak, WhiteSpace, PrevWhiteSpace, FirstWord, + WrapText: Boolean; + Size: TSize; + begin + Result.cx := 0; + Vert := Y; + if AText <> '' then + begin + LineBegin := 1; + LineBreaks := 0; + TextLen := Length(AText); + Width := ClipRect.Right - ClipRect.Left; + CalcRect := taCalcRect in Attributes; + WordBreak := taWordBreak in Attributes; + LineBreak := taLineBreak in Attributes; + WrapText := taWrapText in Attributes; //JR:20091229 + if Output then + begin + EndEllipsis := taEndEllipsis in Attributes; + PathEllipsis := taPathEllipsis in Attributes; + EllipsisWidth := TextExtent(cEllipsis, Length(cEllipsis)).cx; + end; + if WordBreak or LineBreak then + begin + I := LineBegin; + Index := LineBegin; + WhiteSpace := True; + FirstWord := True; + while I <= TextLen + 1 do + begin + PrevWhiteSpace := WhiteSpace; + WhiteSpace := CharInSetEx(AText[I], cWordBreaks + cLineBreaks); + if (not PrevWhiteSpace and WhiteSpace and (I > LineBegin)) + or (not PrevWhiteSpace and WrapText and (I > LineBegin)) then //JR:20091229 + begin + if (WordBreak or WrapText) and (LineBreaks = 0) and not FirstWord then + begin + Size := TextExtent(@AText[LineBegin], I - LineBegin, True); + if Size.cx > Width then + Inc(LineBreaks); + end; + if LineBreaks > 0 then + begin + if Index > LineBegin then + begin + if Output and (Vert >= ClipRect.Top - FontHeight) and (Vert <= ClipRect.Bottom) then + FmtTextOut(Vert, @AText[LineBegin], Index - LineBegin) + else if CalcRect then + Result.cx := Max(Result.cx, TextExtent(@AText[LineBegin], Index - LineBegin, True).cx); + LineBegin := Index; + end; + Inc(Vert, FontHeight * LineBreaks); + LineBreaks := 0; + end; + Index := I; + FirstWord := False; + end; + if LineBreak and (AText[I] = cCR) then + Inc(LineBreaks); + Inc(I); + end; + end; + if LineBegin <= TextLen then + begin + if Output and (Vert >= ClipRect.Top - FontHeight) and (Vert <= ClipRect.Bottom) then + FmtTextOut(Vert, @AText[LineBegin], TextLen - LineBegin + 1) + else if CalcRect then + Result.cx := Max(Result.cx, TextExtent(@AText[LineBegin], TextLen - LineBegin + 1, True).cx); + Inc(Vert, FontHeight * (1 + LineBreaks)); + end; + end; + Result.cy := Vert - Y; + end; + + procedure Initialize; + begin + ClipRect := ARect; + InflateRect(ClipRect, -HPadding, -VPadding); + DC := Canvas.Handle; + FontHeight := GetFontHeight(DC); + end; + +var + Y: Integer; + TmpRect: TRect; + Extent: TSize; + PrevRgn: HRGN; +begin + if taCalcRect in Attributes then + begin + Initialize; + Extent := MeasureOrOutput(0, False); + ARect.Right := ARect.Left + Extent.cx; + ARect.Bottom := ARect.Top + Extent.cy; + end + else if not IsRectEmpty(ARect) then + begin + if taFillRect in Attributes then + DrawFilledRectangle(Canvas, ARect, BackColor); + if AText <> '' then + begin + Initialize; + if not IsRectEmpty(ClipRect) then + begin + case VAlign of + valCenter: + Y := Max(ClipRect.Top, (ClipRect.Bottom + ClipRect.Top - MeasureOrOutput(0, False).cy) div 2); + valBottom: + Y := ClipRect.Bottom - MeasureOrOutput(0, False).cy; + else + Y := ClipRect.Top; + end; + TmpRect := ClipRect; + if taClip in Attributes then + begin + TranslateRectToDevice(DC, TmpRect); + if ExtSelectClipRect(DC, TmpRect, RGN_AND, PrevRgn) then + try + if not (taFillText in Attributes) then + SetBkMode(DC, TRANSPARENT); + MeasureOrOutput(Y, True); + finally + FinalizePrevRgn(DC, PrevRgn); + end; + end else + begin + if not (taFillText in Attributes) then + SetBkMode(DC, TRANSPARENT); + MeasureOrOutput(Y, True); + end; + end; + end; + end; +end; + +procedure DrawEdges(Canvas: TCanvas; const R: TRect; HighlightColor, + ShadowColor: TColor; Flags: Cardinal); +begin + with Canvas do + begin + Brush.Style := bsSolid; + Brush.Color := HighlightColor; + if Flags and BF_LEFT <> 0 then + FillRect(Rect(R.Left, R.Top + 1, R.Left + 1, R.Bottom)); + if Flags and BF_TOP <> 0 then + FillRect(Rect(R.Left, R.Top, R.Right, R.Top + 1)); + Brush.Color := ShadowColor; + if Flags and BF_RIGHT <> 0 then + FillRect(Rect(R.Right - 1, R.Top + 1, R.Right, R.Bottom)); + if Flags and BF_BOTTOM <> 0 then + FillRect(Rect(R.Left + 1, R.Bottom - 1, R.Right - 1, R.Bottom)); + end; +end; + +procedure DrawFilledRectangle(Canvas: TCanvas; const ARect: TRect; BackColor: TColor); +var + DC: HDC; +begin + DC := Canvas.Handle; + SetBkMode(DC, OPAQUE); + SetBkColor(DC, ColorToRGB(BackColor)); + FillRect(DC, ARect, Canvas.Brush.Handle); +end; + +procedure ExcludeShapeFromBaseRect(var BaseRect: TRect; ShapeWidth, ShapeHeight: Integer; + HAlign: TKHAlign; VAlign: TKVAlign; HPadding, VPadding: Integer; + StretchMode: TKStretchMode; out Bounds, Interior: TRect); +var + MaxHeight, MaxWidth, StretchHeight, StretchWidth: Integer; + RatioX, RatioY: Single; +begin + MaxHeight := BaseRect.Bottom - BaseRect.Top - 2 * VPadding; + MaxWidth := BaseRect.Right - BaseRect.Left - HPadding; + if ((MaxWidth <> ShapeWidth) or (MaxHeight <> ShapeHeight)) and ( + (StretchMode = stmZoom) or + (StretchMode = stmZoomInOnly) and (MaxWidth >= ShapeWidth) and (MaxHeight >= ShapeHeight) or + (StretchMode = stmZoomOutOnly) and ((MaxWidth < ShapeWidth) or (MaxHeight < ShapeHeight)) + ) then + begin + RatioX := MaxWidth / ShapeWidth; + RatioY := MaxHeight / ShapeHeight; + if RatioY >= RatioX then + begin + StretchWidth := MaxWidth; + StretchHeight := ShapeHeight * StretchWidth div ShapeWidth; + end else + begin + StretchHeight := MaxHeight; + StretchWidth := ShapeWidth * StretchHeight div ShapeHeight; + end; + end else + begin + StretchHeight := ShapeHeight; + StretchWidth := ShapeWidth; + end; + Bounds := BaseRect; + Interior := BaseRect; + case HAlign of + halLeft: + begin + Inc(BaseRect.Left, StretchWidth + HPadding); + // Bounds.Left remains unchanged + Bounds.Right := BaseRect.Left; + Inc(Interior.Left, HPadding); + end; + halCenter: + begin + BaseRect.Right := BaseRect.Left; // BaseRect empty, no space for next item! + // Bounds remains unchanged + Inc(Interior.Left, HPadding + (MaxWidth - StretchWidth) div 2); + end; + halRight: + begin + Dec(BaseRect.Right, StretchWidth + HPadding); + Bounds.Left := BaseRect.Right; + // Bounds.Right remains unchanged + Interior.Left := BaseRect.Right; + end; + end; + Interior.Right := Interior.Left + StretchWidth; + case VAlign of + valTop: Inc(Interior.Top, VPadding); + valCenter: Inc(Interior.Top, VPadding + (MaxHeight - StretchHeight) div 2); + valBottom: Interior.Top := BaseRect.Bottom - VPadding - StretchHeight; + end; + Interior.Bottom := Interior.Top + StretchHeight; +end; + +function ExtSelectClipRect(DC: HDC; ARect: TRect; Mode: Integer; out PrevRgn: HRGN): Boolean; +var + TmpRgn: HRGN; +begin + PrevRgn := CreateEmptyRgn; + GetClipRgn(DC, PrevRgn); + TmpRgn := CreateEmptyRgn; + try + Result := ExtSelectClipRectEx(DC, ARect, Mode, TmpRgn, PrevRgn) + finally + DeleteObject(TmpRgn); + end; +end; + +function ExtSelectClipRectEx(DC: HDC; ARect: TRect; Mode: Integer; CurRgn, PrevRgn: HRGN): Boolean; +var + RectRgn: HRGN; +begin + RectRgn := CreateRectRgnIndirect(ARect); + try + Result := CombineRgn(CurRgn, PrevRgn, RectRgn, Mode) <> NULLREGION; + if Result then + SelectClipRgn(DC, CurRgn); + finally + DeleteObject(RectRgn); + end; +end; + +procedure FillAroundRect(ACanvas: TCanvas; const Boundary, Interior: TRect; BackColor: TColor); +var + R: TRect; +begin + R := Rect(Boundary.Left, Boundary.Top, Boundary.Right, Interior.Top); + if not IsRectEmpty(R) then DrawFilledRectangle(ACanvas, R, BackColor); + R := Rect(Boundary.Left, Interior.Top, Interior.Left, Interior.Bottom); + if not IsRectEmpty(R) then DrawFilledRectangle(ACanvas, R, BackColor); + R := Rect(Interior.Right, Interior.Top, Boundary.Right, Interior.Bottom); + if not IsRectEmpty(R) then DrawFilledRectangle(ACanvas, R, BackColor); + R := Rect(Boundary.Left, Interior.Bottom, Boundary.Right, Boundary.Bottom); + if not IsRectEmpty(R) then DrawFilledRectangle(ACanvas, R, BackColor); +end; + +procedure FinalizePrevRgn(DC: HDC; ARgn: HRGN); +begin + SelectClipRgn(DC, ARgn); + DeleteObject(ARgn); +end; + +function GetFontHeight(DC: HDC): Integer; +var + TM: TTextMetric; +begin + FillChar(TM, SizeOf(TTextMetric), 0); + GetTextMetrics(DC, TM); + Result := TM.tmHeight; +end; + +function GDICheck(Value: Integer): Integer; +begin + if Value = 0 then + raise EOutOfResources.Create(SGDIError); + Result := Value; +end; + +function ImageByType(const Header: TKImageHeaderString): TGraphic; +begin + if Pos('BM', {$IFDEF COMPILER12_UP}string{$ENDIF}(Header)) = 1 then + Result := TBitmap.Create +{$IFDEF USE_PNG_SUPPORT } + else if (Pos(#137'PNG', {$IFDEF COMPILER12_UP}string{$ENDIF}(Header)) = 1) or + (Pos(#138'MNG', {$IFDEF COMPILER12_UP}string{$ENDIF}(Header)) = 1) then + Result := TKPngImage.Create +{$ENDIF } + else if (Pos(#$FF#$D8, {$IFDEF COMPILER12_UP}string{$ENDIF}(Header)) = 1) then + Result := TJPegImage.Create + else if (Pos(#$FF#$D8, {$IFDEF COMPILER12_UP}string{$ENDIF}(Header)) = 1) then + Result := TIcon.Create + else + Result := nil; +end; + +function IntersectClipRectIndirect(DC: HDC; ARect: TRect): Boolean; +begin + with ARect do + Result := IntersectClipRect(DC, Left, Top, Right, Bottom) <> NULLREGION; +end; + +function IsBrightColor(Color: TColor): Boolean; +begin + Result := CalcLightness(Color) > 0.5; +end; + +function MakeColorRec(R, G, B, A: Byte): TKColorRec; +begin + Result.R := R; + Result.G := G; + Result.B := B; + Result.A := A; +end; + +procedure LoadCustomCursor(Cursor: TCursor; const ResName: string); +begin + Screen.Cursors[Cursor] := + {$IFDEF FPC} + LoadCursorFromLazarusResource(ResName); + {$ELSE} + LoadCursor(HInstance, PChar(ResName)); + {$ENDIF} +end; + +function PixelFormatFromBpp(Bpp: Cardinal): TPixelFormat; +begin + case Bpp of + 1: Result := pf1bit; + 2..4: Result := pf4bit; + 5..8: Result := pf8bit; + 9..16: Result := pf16bit; + else + Result := pf32bit; + end; +end; + +function RectInRegion(Rgn: HRGN; ARect: TRect): Boolean; +{$IFDEF FPC} +var + RectRgn, TmpRgn: HRGN; +{$ENDIF} +begin +{$IFDEF FPC} + RectRgn := CreateRectRgnIndirect(ARect); + try + TmpRgn := CreateEmptyRgn; + try + Result := CombineRgn(TmpRgn, RectRgn, Rgn, RGN_AND) <> NULLREGION; + finally + DeleteObject(TmpRgn); + end; + finally + DeleteObject(RectRgn); + end; +{$ELSE} + Result := Windows.RectInRegion(Rgn, ARect); +{$ENDIF} +end; + +procedure SafeStretchDraw(ACanvas: TCanvas; ARect: TRect; AGraphic: TGraphic; ABackColor: TColor); +{$IFDEF USE_WINAPI} +var + BM: TBitmap; + W, H, MulX, MulY, DivX, DivY: Integer; + R: TRect; +{$ENDIF} +begin +{$IFDEF USE_WINAPI} + if AGraphic.Transparent then + begin + // WinAPI StretchBlt function does not read properly from screen buffer + // so we have to append double buffering + CanvasGetScale(ACanvas, MulX, MulY, DivX, DivY); + W := MulDiv(ARect.Right - ARect.Left, MulX, DivX); + H := MulDiv(ARect.Bottom - ARect.Top, MulY, DivY); + BM := TBitmap.Create; + try + BM.Width := W; + BM.Height := H; + BM.Canvas.Brush := ACanvas.Brush; + R := Rect(0, 0, W, H); + DrawFilledRectangle(BM.Canvas, R, ABackColor); + BM.Canvas.StretchDraw(R, AGraphic); + ACanvas.StretchDraw(ARect, BM); + finally + BM.Free; + end; + end else +{$ENDIF} + ACanvas.StretchDraw(ARect, AGraphic); +end; + +procedure SelectClipRect(DC: HDC; const ARect: TRect); +var + Rgn: HRGN; +begin + Rgn := CreateRectRgnIndirect(ARect); + try + SelectClipRgn(DC, Rgn); + finally + DeleteObject(Rgn); + end; +end; + +procedure StretchBitmap(DestDC: HDC; DestRect: TRect; SrcDC: HDC; SrcRect: TRect); +begin + {$IFDEF USE_WINAPI}Windows.{$ENDIF}StretchBlt(DestDC, + DestRect.Left, DestRect.Top, DestRect.Right - DestRect.Left, DestRect.Bottom - DestRect.Top, + SrcDC, SrcRect.Left, SrcRect.Top, SrcRect.Right - SrcRect.Left, SrcRect.Bottom - SrcRect.Top, + SRCCOPY); +end; + +procedure SwapBR(var ColorRec: TKColorRec); +var + Tmp: Byte; +begin + Tmp := ColorRec.R; + ColorRec.R := ColorRec.B; + ColorRec.B := Tmp; +end; + +function SwitchRGBToBGR(Value: TColor): TColor; +var + B: Byte; +begin + Result := Value; + B := PKColorRec(@Value).B; + PKColorRec(@Result).B := PKColorRec(@Result).R; + PKColorRec(@Result).R := B; +end; + +procedure TranslateRectToDevice(DC: HDC; var ARect: TRect); +var + P: TPoint; +{$IFDEF USE_DC_MAPPING} + {$IFNDEF LCLQT} + WindowExt, ViewportExt: TSize; + {$ENDIF} +{$ENDIF} +begin +{$IFDEF USE_DC_MAPPING} + {$IFNDEF LCLQT} + if not (GetMapMode(DC) in [0, MM_TEXT]) and + Boolean(GetWindowExtEx(DC, {$IFDEF FPC}@{$ENDIF}WindowExt)) and + Boolean(GetViewportExtEx(DC, {$IFDEF FPC}@{$ENDIF}ViewportExt)) then + begin + ARect.Left := MulDiv(ARect.Left, ViewportExt.cx, WindowExt.cx); + ARect.Right := MulDiv(ARect.Right, ViewportExt.cx, WindowExt.cx); + ARect.Top := MulDiv(ARect.Top, ViewportExt.cy, WindowExt.cy); + ARect.Bottom := MulDiv(ARect.Bottom, ViewportExt.cy, WindowExt.cy); + end; + if Boolean(GetViewPortOrgEx(DC, {$IFDEF FPC}@{$ENDIF}P)) then + OffsetRect(ARect, P.X, P.Y); + {$ENDIF} +{$ENDIF} + if Boolean(GetWindowOrgEx(DC, {$IFDEF FPC}@{$ENDIF}P)) then + OffsetRect(ARect, -P.X, -P.Y); +end; + +{ TKAlphaBitmap } + +constructor TKAlphaBitmap.Create; +begin + inherited; + FCanvas := TCanvas.Create; + FCanvas.Handle := CreateCompatibleDC(0); + FDirectCopy := False; + FHandle := 0; +{$IFNDEF USE_WINAPI} + FImage := TLazIntfImage.Create(0, 0); +{$ENDIF} + FHeight := 0; + FOldBitmap := 0; + FPixels := nil; + FWidth := 0; +end; + +constructor TKAlphaBitmap.CreateFromRes(const ResName: string); +var + Stream: {$IFDEF FPC}TLazarusResourceStream{$ELSE}TResourceStream{$ENDIF}; +begin + Create; + try + {$IFDEF FPC} + Stream := TLazarusResourceStream.Create(LowerCase(ResName), 'BMP'); + {$ELSE} + Stream := TResourceStream.Create(HInstance, ResName, RT_RCDATA); + {$ENDIF} + try + LoadFromStream(Stream); + finally + Stream.Free; + end; + except + end; +end; + +destructor TKAlphaBitmap.Destroy; +var + DC: HDC; +begin + inherited; + SetSize(0, 0); +{$IFNDEF USE_WINAPI} + FImage.Free; +{$ENDIF} + DC := FCanvas.Handle; + FCanvas.Handle := 0; + DeleteDC(DC); + FCanvas.Free; +end; + +procedure TKAlphaBitmap.AlphaDrawTo(ACanvas: TCanvas; X, Y: Integer); +begin + AlphaStretchDrawTo(ACanvas, Rect(X, Y, X + FWidth, Y + FHeight)); +end; + +procedure TKAlphaBitmap.AlphaFill(Alpha: Byte; IfEmpty: Boolean); +var + I: Integer; + HasAlpha: Boolean; +begin + HasAlpha := False; + if IfEmpty then + for I := 0 to FWidth * FHeight - 1 do + if FPixels[I].A <> 0 then + begin + HasAlpha := True; + Break; + end; + if not HasAlpha then + for I := 0 to FWidth * FHeight - 1 do + FPixels[I].A := Alpha; +end; + +procedure TKAlphaBitmap.AlphaFill(Alpha: Byte; BlendColor: TColor; Gradient, Translucent: Boolean); +var + I, J, A1, A2, AR, AG, AB, HAlpha: Integer; + HStep, HSum, VStep, VSum: Single; + Scan: PKColorRecs; + CS: TKColorRec; +begin + VSum := 0; VStep := 0; + HSum := 0; HStep := 0; + if Gradient then + begin + VStep := Alpha / FHeight; + VSum := Alpha; + end; + CS.Value := ColorToRGB(BlendColor); +{$IFNDEF USE_WINAPI} + for I := 0 to FHeight - 1 do +{$ELSE} + for I := FHeight - 1 downto 0 do +{$ENDIF} + begin + Scan := ScanLine[I]; + HAlpha := Alpha; + if Gradient then + begin + HStep := HAlpha / FWidth; + HSum := HAlpha; + end; + for J := 0 to FWidth - 1 do with Scan[J] do + begin + A1 := HAlpha; + A2 := 255 - HAlpha; + AR := R * A1 + CS.R * A2; + AG := G * A1 + CS.G * A2; + AB := B * A1 + CS.B * A2; + R := AR shr 8; + G := AG shr 8; + B := AB shr 8; + if Translucent then + A := HAlpha + else + A := 255; + if Gradient then + begin + HAlpha := Round(HSum); + HSum := HSum - HStep; + end; + end; + if Gradient then + begin + Alpha := Round(VSum); + VSum := VSum - VStep; + end; + end; + FPixelsChanged := True; +end; + +procedure TKAlphaBitmap.AlphaStretchDrawTo(ACanvas: TCanvas; + const ARect: TRect); +{$IFDEF USE_WINAPI} +var + I: Integer; + Tmp: TKAlphaBitmap; + Ps, Pd: PKColorRecs; +{$ENDIF} +begin +{$IFNDEF USE_WINAPI} + DrawTo(ACanvas, ARect); +{$ELSE} + Tmp := TKAlphaBitmap.Create; + try + Tmp.SetSize(FWidth, FHeight); + Tmp.DrawFrom(ACanvas, ARect); + for I := 0 to FHeight - 1 do + begin + Ps := ScanLine[I]; + Pd := Tmp.ScanLine[I]; + BlendLine(Ps, Pd, FWidth); + end; + Tmp.PixelsChanged := True; + Tmp.DrawTo(ACanvas, ARect); + finally + Tmp.Free; + end; +{$ENDIF} +end; + +procedure TKAlphaBitmap.CombinePixel(X, Y: Integer; Color: TKColorRec); +var + Index, A1, A2, AR, AG, AB: Integer; +begin + if (X >= 0) and (X < FWidth) and (Y >= 0) and (Y < FHeight) then + begin + SwapBR(Color); + {$IFDEF USE_WINAPI} + Index := (FHeight - Y - 1) * FWidth + X; + {$ELSE} + Index := Y * FWidth + X; + {$ENDIF} + A2 := Color.A; + if A2 = 255 then + FPixels[Index] := Color + else if A2 <> 0 then + begin + A1 := 255 - Color.A; + AR := FPixels[Index].R * A1 + Color.R * A2; + AG := FPixels[Index].G * A1 + Color.G * A2; + AB := FPixels[Index].B * A1 + Color.B * A2; + FPixels[Index].R := AR shr 8; + FPixels[Index].G := AG shr 8; + FPixels[Index].B := AB shr 8; + FPixels[Index].A := 255; + end; + FPixelsChanged := True; + end; +end; + +procedure TKAlphaBitmap.CopyFrom(ABitmap: TKAlphaBitmap); +var + I, Size: Integer; +begin + SetSize(ABitmap.Width, ABitmap.Height); + Size := FWidth * SizeOf(TKColorRec); + for I := 0 to FHeight - 1 do + Move(ABitmap.ScanLine[I]^, ScanLine[I]^, Size); + FPixelsChanged := True; +end; + +procedure TKAlphaBitmap.CopyFromRotated(ABitmap: TKAlphaBitmap); +var + I, J: Integer; + SrcScan, DstScan: PKColorRecs; +begin + SetSize(ABitmap.Height, ABitmap.Width); + for J := 0 to ABitmap.Height - 1 do + begin + SrcScan := ABitmap.ScanLine[J]; + for I := 0 to ABitmap.Width - 1 do + begin + DstScan := ScanLine[ABitmap.Width - I - 1]; + DstScan[J] := SrcScan[I]; + end; + end; + FPixelsChanged := True; +end; + +procedure TKAlphaBitmap.Draw(ACanvas: TCanvas; const ARect: TRect); +begin + if FDirectCopy then + DrawTo(ACanvas, ARect) + else + AlphaStretchDrawTo(ACanvas, ARect); +end; + +procedure TKAlphaBitmap.DrawFrom(ACanvas: TCanvas; const ARect: TRect); +begin + if not Empty then + begin + if not CanvasScaled(ACanvas) then + StretchBitmap(FCanvas.Handle, Rect(0, 0, FWidth, FHeight), ACanvas.Handle, ARect) + else + begin + FCanvas.Brush := ACanvas.Brush; + DrawFilledRectangle(FCanvas, Rect(0, 0, FWidth, FHeight), + {$IFDEF USE_WINAPI}GetBkColor(ACanvas.Handle){$ELSE}clWindow{$ENDIF}); + end; + UpdatePixels; + end; +end; + +procedure TKAlphaBitmap.DrawTo(ACanvas: TCanvas; const ARect: TRect); +begin + if not Empty then + begin + UpdateHandle; + StretchBitmap(ACanvas.Handle, ARect, FCanvas.Handle, Rect(0, 0, FWidth, FHeight)) + end; +end; + +function TKAlphaBitmap.GetEmpty: Boolean; +begin + Result := (FWidth = 0) and (FHeight = 0); +end; + +function TKAlphaBitmap.GetHeight: Integer; +begin + Result := FHeight; +end; + +function TKAlphaBitmap.GetPixel(X, Y: Integer): TKColorRec; +begin + if (X >= 0) and (X < FWidth) and (Y >= 0) and (Y < FHeight) then + begin + {$IFDEF USE_WINAPI} + Result := FPixels[(FHeight - Y - 1) * FWidth + X]; + {$ELSE} + Result := FPixels[Y * FWidth + X]; + {$ENDIF} + SwapBR(Result); + end else + Result := MakeColorRec(0,0,0,0); +end; + +function TKAlphaBitmap.GetTransparent: Boolean; +begin + Result := True; +end; + +function TKAlphaBitmap.GetScanLine(Index: Integer): PKColorRecs; +begin + // no checks here + Result := @FPixels[Index * FWidth]; +end; + +function TKAlphaBitmap.GetHandle: HBITMAP; +begin + Result := FHandle; +end; + +function TKAlphaBitmap.GetWidth: Integer; +begin + Result := FWidth; +end; + +{$IFNDEF FPC} +procedure TKAlphaBitmap.LoadFromClipboardFormat(AFormat: Word; AData: THandle; + APalette: HPALETTE); +begin + // does nothing +end; +{$ENDIF} + +procedure TKAlphaBitmap.LoadFromStream(Stream: TStream); +var + BF: TBitmapFileHeader; + BI: TBitmapInfoHeader; +begin + SetSize(0, 0); + Stream.Read(BF, SizeOf(TBitmapFileHeader)); + Stream.Read(BI, SizeOf(TBitmapInfoHeader)); + if BI.biBitCount = 32 then + begin + SetSize(BI.biWidth, BI.biHeight); + Stream.Read(FPixels^, BI.biSizeImage); + // if bitmap has no alpha channel, create full opacity + AlphaFill($FF, True); + end; + FPixelsChanged := True; +end; + +procedure TKAlphaBitmap.MirrorHorz; +var + I, J, Index: Integer; + SrcScan: PKColorRecs; + Buf: TKColorRec; +begin + for I := 0 to FHeight - 1 do + begin + SrcScan := ScanLine[I]; + Index := FWidth - 1; + for J := 0 to (FWidth shr 1) - 1 do + begin + Buf := SrcScan[Index]; + SrcScan[Index] := SrcScan[J]; + SrcScan[J] := Buf; + Dec(Index); + end; + end; + FPixelsChanged := True; +end; + +procedure TKAlphaBitmap.MirrorVert; +var + I, Size, Index: Integer; + SrcScan, DstScan: PKColorRecs; + Buf: PKColorRec; +begin + Size:= FWidth * SizeOf(TKColorRec); + Index := FHeight - 1; + GetMem(Buf, Size); + try + for I := 0 to (FHeight shr 1) - 1 do + begin + SrcScan := ScanLine[I]; + DstScan := ScanLine[Index]; + Move(SrcScan^, Buf^, Size); + Move(DstScan^, SrcScan^, Size); + Move(Buf^, DstScan^, Size); + Dec(Index); + end; + finally + FreeMem(Buf); + end; + FPixelsChanged := True; +end; + +{$IFNDEF FPC} +procedure TKAlphaBitmap.SaveToClipboardFormat(var AFormat: Word; + var AData: THandle; var APalette: HPALETTE); +begin + // does nothing +end; +{$ENDIF} + +procedure TKAlphaBitmap.SaveToStream(Stream: TStream); +var + Size: Integer; + BF: TBitmapFileHeader; + BI: TBitmapInfoHeader; +begin + Size := FWidth * FHeight * 4; + FillChar(BF, SizeOf(TBitmapFileHeader), 0); + BF.bfType := $4D42; + BF.bfSize := SizeOf(TBitmapFileHeader) + SizeOf(TBitmapInfoHeader) + Size; + BF.bfOffBits := SizeOf(TBitmapFileHeader) + SizeOf(TBitmapInfoHeader); + Stream.Write(BF, SizeOf(TBitmapFileHeader)); + FillChar(BI, SizeOf(TBitmapInfoHeader), 0); + BI.biSize := SizeOf(TBitmapInfoHeader); + BI.biWidth := FWidth; + BI.biHeight := FHeight; + BI.biPlanes := 1; + BI.biBitCount := 32; + BI.biCompression := BI_RGB; + BI.biSizeImage := Size; + Stream.Write(BI, SizeOf(TBitmapInfoHeader)); + Stream.Write(FPixels^, Size); +end; + +procedure TKAlphaBitmap.SetHeight(Value: Integer); +begin + SetSize(FWidth, Value); +end; + +procedure TKAlphaBitmap.SetPixel(X, Y: Integer; Value: TKColorRec); +begin + if (X >= 0) and (X < FWidth) and (Y >= 0) and (Y < FHeight) then + begin + SwapBR(Value); + {$IFDEF USE_WINAPI} + FPixels[(FHeight - Y - 1) * FWidth + X] := Value; + {$ELSE} + FPixels[Y * FWidth + X] := Value; + {$ENDIF} + FPixelsChanged := True; + end; +end; + +procedure TKAlphaBitmap.SetSize(AWidth, AHeight: Integer); +var +{$IFNDEF USE_WINAPI} + ImgFormatDescription: TRawImageDescription; +{$ELSE} + BI: TBitmapInfoHeader; +{$ENDIF} +begin + AWidth := Max(AWidth, 0); + AHeight := Max(AHeight, 0); + if (AWidth <> FWidth) or (AHeight <> FHeight) then + begin + FWidth := AWidth; + FHeight := AHeight; + if FHandle <> 0 then + begin + SelectObject(FCanvas.Handle, FOldBitmap); + DeleteObject(FHandle); + FHandle := 0; + {$IFNDEF USE_WINAPI} + DeleteObject(FMaskHandle); + FMaskHandle := 0; + {$ENDIF} + end; + {$IFNDEF USE_WINAPI} + FImage.SetSize(0, 0); + {$ENDIF} + FPixels := nil; + if (FWidth <> 0) and (FHeight <> 0) then + begin + {$IFNDEF USE_WINAPI} + ImgFormatDescription.Init_BPP32_B8G8R8A8_BIO_TTB(FWidth,FHeight); + FImage.DataDescription := ImgFormatDescription; + FPixelsChanged := True; + UpdateHandle; + {$ELSE} + FillChar(BI, SizeOf(TBitmapInfoHeader), 0); + BI.biSize := SizeOf(TBitmapInfoHeader); + BI.biWidth := FWidth; + BI.biHeight := FHeight; + BI.biPlanes := 1; + BI.biBitCount := 32; + BI.biCompression := BI_RGB; + FHandle := GDICheck(CreateDIBSection(FCanvas.Handle, PBitmapInfo(@BI)^, DIB_RGB_COLORS, Pointer(FPixels), 0, 0)); + FOldBitmap := SelectObject(FCanvas.Handle, FHandle); + {$ENDIF} + end; + end; +end; + +procedure TKAlphaBitmap.SetWidth(Value: Integer); +begin + SetSize(Value, FWidth); +end; + +procedure TKAlphaBitmap.SetTransparent(Value: Boolean); +begin + // does nothing +end; + +procedure TKAlphaBitmap.UpdateHandle; +begin +{$IFNDEF USE_WINAPI} + if FPixelsChanged then + begin + PixelsChanged := False; + if FHandle <> 0 then + begin + DeleteObject(FMaskHandle); + DeleteObject(SelectObject(FCanvas.Handle, FOldBitmap)); + end; + FImage.CreateBitmaps(FHandle, FMaskHandle, False); + FOldBitmap := SelectObject(FCanvas.Handle, FHandle); + FPixels := PKColorRecs(FImage.PixelData); + end; +{$ENDIF} +end; + +procedure TKAlphaBitmap.UpdatePixels; +begin +{$IFNDEF USE_WINAPI} + FImage.LoadFromDevice(FCanvas.Handle); + FPixelsChanged := True; + UpdateHandle; +{$ENDIF} +end; + +{$IFDEF USE_WINAPI} +const + cLayeredWndClass = 'KControls drag window'; + +function DragWndProc(Window: HWnd; Msg, WParam, LParam: Longint): Longint; stdcall; +var + DC: HDC; + PS: TPaintStruct; + AWindow: TKDragWindow; +begin + case Msg of + WM_PAINT: + begin + AWindow := TKDragWindow(GetWindowLong(Window, GWL_USERDATA)); + if (AWindow <> nil) and AWindow.BitmapFilled then + begin + if wParam = 0 then + DC := BeginPaint(Window, PS) + else + DC := wParam; + try + BitBlt(DC, 0, 0, AWindow.Bitmap.Width, AWindow.Bitmap.Height, + AWindow.Bitmap.Canvas.Handle, 0, 0, SRCCOPY); + finally + if wParam = 0 then EndPaint(Window, PS); + end; + end; + Result := 1; + end; + else + Result := DefWindowProc(Window, Msg, WParam, LParam); + end; +end; + +{$ELSE} + +type + + { TKDragForm } + + TKDragForm = class(THintWindow) + private + FWindow: TKDragWindow; + procedure WMEraseBkGnd(var Msg: TLMessage); message LM_ERASEBKGND; + protected + procedure Paint; override; + public + constructor CreateDragForm(AWindow: TKDragWindow); + end; + +{ TKDragForm } + +constructor TKDragForm.CreateDragForm(AWindow: TKDragWindow); +begin + inherited Create(nil); + FWindow := AWindow; + ShowInTaskBar := stNever; +end; + +procedure TKDragForm.Paint; +begin + if FWindow.Active and FWindow.BitmapFilled then + Canvas.Draw(0, 0, FWindow.FBitmap); +end; + +procedure TKDragForm.WMEraseBkGnd(var Msg: TLMessage); +begin + Msg.Result := 1; +end; + +{$ENDIF} + +constructor TKDragWindow.Create; +{$IFDEF USE_WINAPI} +var + Cls: Windows.TWndClass; + ExStyle: Cardinal; +{$ENDIF} +begin + inherited; + FActive := False; + FBitmap := TKAlphaBitmap.Create; + FInitialPos := Point(0, 0); +{$IFDEF USE_WINAPI} + FUpdateLayeredWindow := GetProcAddress(GetModuleHandle('user32.dll'), 'UpdateLayeredWindow'); + FLayered := Assigned(FUpdateLayeredWindow); + Cls.style := CS_SAVEBITS; + Cls.lpfnWndProc := @DragWndProc; + Cls.cbClsExtra := 0; + Cls.cbWndExtra := 0; + Cls.hInstance := HInstance; + Cls.hIcon := 0; + Cls.hCursor := 0; + Cls.hbrBackground := 0; + Cls.lpszMenuName := nil; + Cls.lpszClassName := cLayeredWndClass; + Windows.RegisterClass(Cls); + ExStyle := WS_EX_TOOLWINDOW or WS_EX_TOPMOST; + if FLayered then + ExStyle := ExStyle or WS_EX_LAYERED or WS_EX_TRANSPARENT; + FWindow := CreateWindowEx(ExStyle, cLayeredWndClass, '', WS_POPUP, + Integer(CW_USEDEFAULT), Integer(CW_USEDEFAULT), Integer(CW_USEDEFAULT), + Integer(CW_USEDEFAULT), 0, 0, HInstance, nil); + Windows.SetWindowLong(FWindow, GWL_USERDATA, Integer(Self)); +{$ELSE} + FDragForm := TKDragForm.CreateDragForm(Self); + FLayered := False; +{$ENDIF} +end; + +destructor TKDragWindow.Destroy; +begin + inherited; + Hide; +{$IFDEF USE_WINAPI} + DestroyWindow(FWindow); + Windows.UnregisterClass(cLayeredWndClass, HInstance); +{$ELSE} + FDragForm.Free; +{$ENDIF} + FBitmap.Free; +end; + +procedure TKDragWindow.Hide; +begin + if FActive then + begin + {$IFDEF USE_WINAPI} + ShowWindow(FWindow, SW_HIDE); + {$ELSE} + FDragForm.Hide; + {$ENDIF} + FActive := False; + end; +end; + +procedure TKDragWindow.Show(IniCtrl: TCustomControl; const ARect: TRect; + const InitialPos, CurrentPos: TPoint; MasterAlpha: Byte; Gradient: Boolean); +var + Org: TPoint; + W, H: Integer; + ScreenDC: HDC; +begin + if not (IniCtrl is TKCustomControl) then Exit; + if not FActive then + begin + FActive := True; + FBitmapFilled := False; + FControl := IniCtrl; + FMasterAlpha := MasterAlpha; + FGradient := Gradient; + FInitialPos := InitialPos; + W := ARect.Right - ARect.Left; + H := ARect.Bottom - ARect.Top; + FBitmap.SetSize(W, H); + Org := IniCtrl.ClientToScreen(ARect.TopLeft); + ScreenDC := GetDC(0); + try + FAlphaEffects := GetDeviceCaps(ScreenDC, BITSPIXEL) >= 15; + // because alpha blending is not nice elsewhere + finally + ReleaseDC(0, ScreenDC); + end; + // to be compatible with all LCL widgetsets we must copy the control's part + // while painting in TKCustomControl.Paint! + TKCustomControl(FControl).MemoryCanvas := FBitmap.Canvas; + TKCustomControl(FControl).MemoryCanvasRect := ARect; + TKCustomControl(FControl).Repaint; + {$IFDEF USE_WINAPI} + if FLayered then with FBlend do + begin + BlendOp := AC_SRC_OVER; + BlendFlags := 0; + SourceConstantAlpha := 255; + if FAlphaEffects then + AlphaFormat := AC_SRC_ALPHA + else + AlphaFormat := 0; + end; + SetWindowPos(FWindow, 0, Org.X, Org.Y, W, H, + SWP_NOACTIVATE or SWP_NOZORDER); + {$ELSE} + FDragForm.SetBounds(Org.X, Org.Y, W, H); + {$ENDIF} + Move(CurrentPos); + end; +end; + +procedure TKDragWindow.Move(const NewPos: TPoint); +var + R: TRect; + DX, DY: Integer; + BlendColor: TColor; +{$IFDEF USE_WINAPI} + ScreenDC: HDC; + CanvasOrigin: TPoint; +{$ENDIF} +begin + if FActive then + begin + if (TKCustomControl(FControl).MemoryCanvas = nil) and not FBitmapFilled then + begin + FBitmapFilled := True; + FBitmap.UpdatePixels; + if FAlphaEffects then + begin + if FLayered then + BlendColor := clBlack + else + BlendColor := clWhite; + FBitmap.AlphaFill(FMasterAlpha, BlendColor, FGradient, FLayered); + FBitmap.UpdateHandle; + end; + end; + DX := NewPos.X - FInitialPos.X; + DY := NewPos.Y - FInitialPos.Y; + if (DX <> 0) or (DY <> 0) then + begin + FInitialPos := NewPos; + {$IFDEF USE_WINAPI} + GetWindowRect(FWindow, R); + OffsetRect(R, DX, DY); + if FLayered then + begin + R.Right := FBitmap.Width; + R.Bottom := FBitmap.Height; + CanvasOrigin := Point(0, 0); + ScreenDC := GetDC(0); + try + if FUpdateLayeredWindow(FWindow, ScreenDC, @R.TopLeft, PSize(@R.BottomRight), + FBitmap.Canvas.Handle, @CanvasOrigin, clNone, @FBlend, ULW_ALPHA) then + if FBitmapFilled then + ShowWindow(FWindow, SW_SHOWNOACTIVATE); + finally + ReleaseDC(0, ScreenDC); + end; + end + else if FBitmapFilled then + SetWindowPos(FWindow, 0, R.Left, R.Top, 0, 0, + SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER or SWP_SHOWWINDOW); + {$ELSE} + R := FDragForm.BoundsRect; + OffsetRect(R, DX, DY); + FDragForm.BoundsRect := R; + if FBitmapFilled then + begin + FDragForm.Visible := True; + SetCaptureControl(FControl); + end; + {$ENDIF} + end; + end; +end; + +{ TKHintWindow } + +constructor TKHintWindow.Create(AOwner: TComponent); +begin + inherited; +{$IFDEF FPC} + ShowInTaskBar := stNever; +{$ENDIF} + DoubleBuffered := True; +end; + +procedure TKHintWindow.ShowAt(const Origin: TPoint); +begin + ActivateHint(Rect(Origin.X, Origin.Y, Origin.X + FExtent.X + 10, Origin.Y + FExtent.Y + 10), ''); +end; + +procedure TKHintWindow.WMEraseBkGnd(var Msg: TLMessage); +begin + Msg.Result := 1; +end; + +{ TKTextHint } + +constructor TKTextHint.Create(AOwner: TComponent); +begin + inherited; + FText := ''; +end; + +procedure TKTextHint.Paint; +var + R: TRect; +begin + Canvas.Brush.Style := bsSolid; + Canvas.Brush.Color := clInfoBk; + Canvas.FillRect(ClientRect); + Canvas.Brush.Style := bsClear; + R := Rect(0, 0, FExtent.X + 10, FExtent.Y + 10); + DrawAlignedText(Canvas, R, halLeft, valCenter, + 5, 5, FText, clInfoBk, [taEndEllipsis, taWordBreak, taLineBreak]) +end; + +procedure TKTextHint.SetText(const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); +var + R: TRect; +begin + if Value <> FText then + begin + FText := Value; + R := Rect(0, 0, 300, 0); + DrawAlignedText(Canvas, R, halLeft, valCenter, + 0, 0, FText, clInfoBk, [taCalcRect, taWordBreak, taLineBreak]); + FExtent.X := R.Right - R.Left; + FExtent.Y := R.Bottom - R.Top; + end; +end; + +{ TKGraphicHint } + +constructor TKGraphicHint.Create(AOwner: TComponent); +begin + inherited; + FGraphic := nil; +{$IFDEF FPC} + ShowInTaskBar := stNever; +{$ENDIF} + DoubleBuffered := True; +end; + +procedure TKGraphicHint.Paint; +begin + Canvas.Brush.Style := bsSolid; + Canvas.Brush.Color := clInfoBk; + Canvas.FillRect(ClientRect); + if Assigned(FGraphic) then + Canvas.Draw(5, 5, FGraphic) +end; + +procedure TKGraphicHint.SetGraphic(const Value: TGraphic); +begin + if Value <> FGraphic then + begin + FGraphic := Value; + FExtent.X := FGraphic.Width; + FExtent.Y := FGraphic.Height; + end; +end; + +end. diff --git a/components/kcontrols/source/kgrids.lrs b/components/kcontrols/source/kgrids.lrs new file mode 100755 index 000000000..5cc3f79ae --- /dev/null +++ b/components/kcontrols/source/kgrids.lrs @@ -0,0 +1,101 @@ +LazarusResources.Add('kgrid_hci_hbegin','BMP',[ + 'BMZ'#0#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#3#0#0#0#3#0#0#0#1#0' '#0#0#0#0#0'$'#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#231#5#0#0#252#6#0'-'#255'2'#0#0#209#5#0 + +#0#229#5#0#0#245#6#0#0#200#5#0#0#209#5#0#0#218#5#0 +]); +LazarusResources.Add('kgrid_hci_hcenter','BMP',[ + 'BMN'#0#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#2#0#0#0#3#0#0#0#1#0' '#0#0#0#0#0#24#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0':'#255'?'#0':'#255'?'#0#0#249#6#0#0#249#6 + +#0#0#221#5#0#0#221#5#0 +]); +LazarusResources.Add('kgrid_hci_hend','BMP',[ + 'BMZ'#0#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#3#0#0#0#3#0#0#0#1#0' '#0#0#0#0#0'$'#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'F'#255'J'#0'm'#255'p'#0#151#255#153#0#0 + +#253#6#0'.'#255'3'#0'o'#255'r'#0#0#225#5#0#0#239#6#0#21#255#27#0 +]); +LazarusResources.Add('kgrid_hci_vbegin','BMP',[ + 'BMZ'#0#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#3#0#0#0#3#0#0#0#1#0' '#0#0#0#0#0'$'#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#218#5#0#0#245#6#0'-'#255'2'#0#0#209#5#0 + +#0#229#5#0#0#252#6#0#0#200#5#0#0#209#5#0#0#231#5#0 +]); +LazarusResources.Add('kgrid_hci_vcenter','BMP',[ + 'BMN'#0#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#3#0#0#0#2#0#0#0#1#0' '#0#0#0#0#0#24#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#221#5#0#0#249#6#0':'#255'?'#0#0#221#5#0 + +#0#249#6#0':'#255'?'#0 +]); +LazarusResources.Add('kgrid_hci_vend','BMP',[ + 'BMZ'#0#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#3#0#0#0#3#0#0#0#1#0' '#0#0#0#0#0'$'#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'F'#255'J'#0'm'#255'p'#0#151#255#153#0#0 + +#253#6#0'.'#255'3'#0'o'#255'r'#0#0#225#5#0#0#239#6#0#21#255#27#0 +]); +LazarusResources.Add('kgrid_drag_arrow','BMP',[ + 'BM'#26#2#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#11#0#0#0#11#0#0#0#1#0' '#0#0#0#0#0#228 + +#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 + +'5'#0#0#0#179#0#0#0'5'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#0#0#0'5'#0#0#0#179#8#175#8#255#0#0#0#179#0#0#0'5'#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#0'5'#0#0#0#179#15#200#15#255'/'#227'/'#255'E'#204'E'#255 + +#0#0#0#179#0#0#0'5'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'5'#0#0#0#179#9#199#9#255',' + +#226','#255'l'#236'l'#255#153#240#153#255#131#222#131#255#0#0#0#179#0#0#0'5' + +#0#0#0#0#0#0#0'5'#0#0#0#179#1#201#1#255#15#223#15#255'C'#229'C'#255#147#240 + +#147#255#191#247#191#255#175#244#175#255']'#202']'#255#0#0#0#179#0#0#0'5'#0#0 + +#0#179#0#0#0#255#0#0#0#255#0#0#0#255'A'#231'A'#255#147#240#147#255#191#247 + +#191#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#179#0#0#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#255'4'#228'4'#255#130#238#130#255#179#245#179#255#0#0#0#255#0#0#0#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255''''#226''''#255'l'#235'l'#255 + +#156#242#156#255#0#0#0#255#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#0#255#21#223#21#255'A'#230'A'#255'a'#234'a'#255#0#0#0#255#0#0#0#0#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#7#222#7#255#21#223#21#255'!'#225 + +'!'#255#0#0#0#255#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#0 + +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#0#0#0#0#0#0#0#0#0 +]); +LazarusResources.Add('kgrid_sort_arrow','BMP',[ + 'BMf'#2#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#14#0#0#0#10#0#0#0#1#0' '#0#0#0#0#0'0'#2 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'Z'#0#0#0'Z'#0#0#0#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#0'Z'#0#0#0#255#0#0#0#255#0#0#0'Z'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'Z'#0#0#0#255'q'#255'q'#255'y'#255'y' + +#255#0#0#0#255#0#0#0'Z'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#0#0#0'Z'#0#0#0#255#153#255#153#255#180#255#180#255#195#255#195#255#189#255 + +#189#255#0#0#0#255#0#0#0'Z'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'Z' + +#0#0#0#255#138#255#138#255#172#255#172#255#208#255#208#255#241#255#241#255 + +#225#255#225#255#189#255#189#255#0#0#0#255#0#0#0'Z'#0#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#0'Z'#0#0#0#255'O'#255'O'#255'n'#255'n'#255#136#255#136#255#158#255#158#255 + +#169#255#169#255#165#255#165#255#147#255#147#255'|'#255'|'#255#0#0#0#255#0#0 + +#0'Z'#0#0#0#0#0#0#0'Z'#0#0#0#255#6#255#6#255'!'#255'!'#255'9'#255'9'#255'K' + +#255'K'#255'Y'#255'Y'#255'_'#255'_'#255']'#255']'#255'R'#255'R'#255'B'#255'B' + +#255','#255','#255#0#0#0#255#0#0#0'Z'#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255 + +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0 + +#255#0#0#0#255#0#0#0#255#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +]); +LazarusResources.Add('kgrid_cursor_hresize','CUR',[ + #0#0#2#0#1#0' '#0#0#15#0#15#0'0'#1#0#0#22#0#0#0'('#0#0#0' '#0#0#0'@'#0#0#0#1 + +#0#1#0#0#0#0#0#128#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#3#192#0#0#2'@'#0 + +#0#2'@'#0#0#2'@'#0#0#2'@'#0#0'2L'#0#0'RJ'#0#0#158'y'#0#1#0#0#128#1#0#0#128#0 + +#158'y'#0#0'RJ'#0#0'2L'#0#0#2'@'#0#0#2'@'#0#0#2'@'#0#0#2'@'#0#0#3#192#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255#255#255#255 + +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255 + +#255#255#255#255#252'?'#255#255#252'?'#255#255#252'?'#255#255#252'?'#255#255 + +#252'?'#255#255#204'3'#255#255#140'1'#255#255#0#0#255#254#0#0#127#254#0#0#127 + +#255#0#0#255#255#140'1'#255#255#204'3'#255#255#252'?'#255#255#252'?'#255#255 + +#252'?'#255#255#252'?'#255#255#252'?'#255#255#255#255#255#255#255#255#255#255 + +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255 +]); +LazarusResources.Add('kgrid_cursor_vresize','CUR',[ + #0#0#2#0#1#0' '#0#0#15#0#15#0'0'#1#0#0#22#0#0#0'('#0#0#0' '#0#0#0'@'#0#0#0#1 + +#0#1#0#0#0#0#0#128#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#128#0#0#2'@'#0 + +#0#4' '#0#0#8#16#0#0#14'p'#0#0#2'@'#0#0#2'@'#0#1#254#127#128#1#0#0#128#1#0#0 + +#128#1#254#127#128#0#2'@'#0#0#2'@'#0#0#14'p'#0#0#8#16#0#0#4' '#0#0#2'@'#0#0#1 + +#128#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255 + +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255 + +#255#255#255#255#255#255#255#254#127#255#255#252'?'#255#255#248#31#255#255 + +#240#15#255#255#240#15#255#255#252'?'#255#255#252'?'#255#254#0#0#127#254#0#0 + +#127#254#0#0#127#254#0#0#127#255#252'?'#255#255#252'?'#255#255#240#15#255#255 + +#240#15#255#255#248#31#255#255#252'?'#255#255#254#127#255#255#255#255#255#255 + +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255 + +#255#255#255#255 +]); diff --git a/components/kcontrols/source/kgrids.pas b/components/kcontrols/source/kgrids.pas new file mode 100755 index 000000000..46cec9edb --- /dev/null +++ b/components/kcontrols/source/kgrids.pas @@ -0,0 +1,12827 @@ + { @abstract(This unit contains the TKGrid component and all supporting classes) + @author(Tomas Krysl (tk@tkweb.eu)) + @created(15 Oct 2006) + @lastmod(07 Dec 2010) + + Copyright © 2006 Tomas Krysl (tk@@tkweb.eu)

+ + This unit provides an enhanced replacement for components contained + in Grids.pas. Major features: +
    +
  • 95% compatible with TDraw(String)Grid
  • +
  • any TWinControl descendant can be used as inplace editor
  • +
  • cell clipping and double buffering
  • +
  • cell merging/splitting
  • +
  • column/row/grid autosizing
  • +
  • cross platform control in Lazarus
  • +
  • index mapping - current column/row indexes can be mapped to their initial values
  • +
  • last row/column aligning (no scrollbar)
  • +
  • printing and previewing
  • +
  • row/column hiding with optional visual indication
  • +
  • rows, columns and cells are classes
  • +
  • several styles possible when moving/sizing cells
  • +
  • sorting interface
  • +
  • Unicode control
  • +
  • various text output attributes (multiline text, end ellipsis etc.)
  • +
  • versatile cell painting interface
  • +
  • virtual grid option
  • +
+ + License:
+ This code is distributed as a freeware. You are free to use it as part + of your application for any purpose including freeware, commercial and + shareware applications. The origin of this source code must not be + misrepresented; you must not claim your authorship. You may modify this code + solely for your own purpose. Please feel free to contact the author if you + think your changes might be useful for other users. You may distribute only + the original package. The author accepts no liability for any damage + that may result from using this code. } + +unit KGrids; + +{$include kcontrols.inc} +{$WEAKPACKAGEUNIT ON} + +interface + +uses +{$IFDEF FPC} + LCLType, LCLIntf, LMessages, LCLProc, LResources, +{$ELSE} + Windows, Messages, +{$ENDIF} + SysUtils, Classes, Graphics, Controls, Forms, StdCtrls, ExtCtrls, + KFunctions, KGraphics, KControls, Types +{$IFDEF TKGRID_USE_JCL} + , JclUnicode +{$ENDIF} + ; + +type + { Declares possible values for the Mask parameter in the @link(TKCustomGrid.GetAxisInfoHorz) + or @link(TKCustomGrid.GetAxisInfoVert) functions. } + TKGridAxisInfoMaskMembers = ( + { The FixedBoundary field in the @link(TKGridAxisInfo) structure will be evaluated. } + aiFixedParams, + { The GridExtent field in the @link(TKGridAxisInfo) structure will be evaluated. } + aiGridExtent, + { The GridBoundary and GridCells fields in the @link(TKGridAxisInfo) structure will be evaluated. } + aiGridBoundary, + { The FullVisBoundary and FullVisCells fields in the @link(TKGridAxisInfo) structure will be evaluated. } + aiFullVisBoundary + ); + + { Set type for @link(TKGridAxisInfoMaskMembers) enumeration. } + TKGridAxisInfoMask = set of TKGridAxisInfoMaskMembers; + + { Method type for the CellExtent field in the @link(TKGridAxisInfo) structure. } + TKGridGetExtentFunc = function(Index: Integer): Integer of object; + + { Method type for the CanResize field in the @link(TKGridAxisInfo) structure. } + TKGridCanResizeFunc = function(var Index, Pos: Integer): Boolean of object; + + { @abstract(Declares a structure returned by the @link(TKCustomGrid.GetAxisInfoHorz) + or @link(TKCustomGrid.GetAxisInfoVert) functions) + This structure contains information either about columns or rows, depending on what + function returned the structure. +
    + Members: +
  • InfoMask - set of parameters that specify what fields in this structure + need to be evaluated.
  • +
  • AlignLastCell - specifies if the last cell is aligned to client + area extent - see @link(goAlignLastCol) or @link(goAlignLastRow) for details.
  • +
  • FixedSelectable - reflects the gxEditFixedCols or gxEditFixedRows.
  • +
  • CanResize - this is the pointer to a function that determines + if a column or row can be resized - i.e. either BeginColSizing or BeginRowSizing methods.
  • +
  • CellExtent - this is the pointer to a function that evaluates cell + width or height - i.e. either GetColWidths or GetColHeights (private members).
  • +
  • EffectiveSpacing - specifies the effective space between cells + as returned by @link(TKCustomGrid.EffectiveColSpacing) or + @link(TKCustomGrid.EffectiveRowSpacing).
  • +
  • FixedCellCount - specifies the amount of fixed columns or rows - + see @link(TKCustomGrid.FixedCols) or @link(TKCustomGrid.FixedRows) for details.
  • +
  • FirstGridCell - specifies the first visible non-fixed cell as given + by @link(TKCustomGrid.LeftCol) or @link(TKCustomGrid.TopRow).
  • +
  • FirstGridCellExtent - specifies the maximum value for the first visible + non-fixed cell as given by TKCustomGrid.FTopLeftExtent.
  • +
  • ClientExtent - this is either the TControl.ClientWidth or + TControl.ClientHeight value.
  • +
  • MinCellExtent - specifies the minimum cell extent as given by + @link(TKCustomGrid.InternalGetMinColWidth) or @link(TKCustomGrid.InternalGetMinRowHeight).
  • +
  • MaxCellExtent - specifies the maximum cell extent as given by + @link(TKCustomGrid.InternalGetMaxColWidth) or @link(TKCustomGrid.InternalGetMaxRowHeight).
  • +
  • TotalCellCount - specifies the total cell amount in desired direction + as given by @link(TKCustomGrid.ColCount) or @link(TKCustomGrid.RowCount).
  • +
  • FixedBoundary - specifies the point in pixels where the + first non-fixed cell begins.
  • +
  • GridBoundary - specifies the grid extent as returned by the + @link(TKCustomGrid.GridWidth) or @link(TKCustomGrid.GridHeight) properties.
  • +
  • GridCells - gives the amount of cells that correspond to GridBoundary.
  • +
  • FullVisBoundary - specifies the point in pixels where the + last fully visible cell ends.
  • +
  • FullVisCells - gives the amount of cells that correspond to FullVisBoundary.
  • +
  • GridExtent - returns the extent of all cells in the grid.
  • +
} + TKGridAxisInfo = record + InfoMask: TKGridAxisInfoMask; + // col/row independent parameters + AlignLastCell: Boolean; + FixedSelectable: Boolean; + CanResize: TKGridCanResizeFunc; + CellExtent: TKGridGetExtentFunc; + EffectiveSpacing: TKGridGetExtentFunc; + FixedCellCount: Integer; + FirstGridCell: Integer; + FirstGridCellExtent: Integer; + ClientExtent: Integer; + MinCellExtent: TKGridGetExtentFunc; + MaxCellExtent: TKGridGetExtentFunc; + TotalCellCount: Integer; + ScrollOffset: Integer; + // calculated parameters + FixedBoundary: Integer; + GridBoundary: Integer; + GridCells: Integer; + FullVisBoundary: Integer; + FullVisCells: Integer; + GridExtent: Int64; + end; + + { @abstract(Declares a structure returned by the + @link(TKCustomGrid.GetAxisInfoBoth) function) +
    + Members: +
  • Horz - structure as returned by @link(TKCustomGrid.GetAxisInfoHorz).
  • +
  • Vert - structure as returned by @link(TKCustomGrid.GetAxisInfoVert).
  • +
} + TKGridAxisInfoBoth = record + Horz, Vert: TKGridAxisInfo; + end; + + { Declares possible values for the Flags parameter in the + @link(TKCustomGrid.UpdateAxes) method. } + TKGridAxisUpdateFlag = ( + { Forces the @link(TKCustomGrid.OnColWidthsChanged) and/or + @link(TKCustomGrid.OnRowHeightsChanged) to be called even if no column width/ + row height has been modified by this call of UpdateAxes. } + afCallEvent, + { Ensures all columns/rows have at least the minimum width/height as specified + by @link(TKCustomGrid.MinColWidth)/@link(TKCustomGrid.MinRowHeight). } + afCheckMinExtent + ); + + { Set type for @link(TKGridAxisUpdateFlags) enumeration. } + TKGridAxisUpdateFlags = set of TKGridAxisUpdateFlag; + + { Declares possible values for the State parameter in the + @link(TKCustomGrid.SuggestDrag) or @link(TKCustomGrid.SuggestSizing) + functions. } + TKGridCaptureState = ( + { Suggestion is about to start - e.g. user clicked the movable column by mouse. } + csStart, + { Suggestion is about to temporarily hide - e.g. user drags a column by mouse + and the grid needs to be updated. } + csHide, + { Suggestion is about to show again - e.g. user drags a column by mouse + and the grid was updated. } + csShow, + { Suggestion is about to stop - e.g. user released the mouse button + and the dragged column need to be actually moved. } + csStop + ); + + { @abstract(Declares a structure that holds both column and row span of a cell) +
    + Members: +
  • ColSpan - column span.
  • +
  • RowSpan - row span.
  • +
} + TKGridCellSpan = record + ColSpan: Integer; + RowSpan: Integer; + end; + + { @abstract(Declares a structure that hold both column and row index of a cell) +
    + Members: +
  • Col - coordinate or index of a column.
  • +
  • Row - coordinate or index of a row.
  • +
} + TKGridCoord = record + Col: Integer; + Row: Integer; + end; + + { Declares possible indexes e.g. for the @link(TKGridColors.Color) property. } + TKGridColorIndex = Integer; + + { Declares possible values for the @link(TKGridColors.ColorScheme) property. } + TKGridColorScheme = ( + { GetColor returns normal color currently defined for each item. } + csNormal, + { GetColor returns gray for text. } + csGrayed, + { GetColor returns brighter version of normal color. } + csBright, + { GetColor returns grayscaled color versions. } + csGrayScale + ); + + { Method type for the Compare parameter e.g. in the + @link(TKCustomGrid.InternalQuickSortNR) method. } + TKGridCompareProc = function(ByIndex, Index1, Index2: Integer): Integer of object; + + { Declares possible values for the @link(TKCustomGrid.DisabledDrawStyle) property. } + TKGridDisabledDrawStyle = ( + { The lines will be painted with brighter colors when control is disabled. } + ddBright, + { The lines will be painted with gray text and white background when control is disabled. } + ddGrayed, + { The lines will be painted normally when control is disabled. } + ddNormal + ); + + { Declares possible values for the @link(TKCustomGrid.DragStyle) property. } + TKGridDragStyle = ( + { The moved column or row is displayed beneath mouse cursor in a layered window (Win2k+) + or white window (other OS) with fading opacity. } + dsLayeredConst, + { The moved column or row is displayed beneath mouse cursor in a layered window (Win2k+) + or white window (other OS) with constant opacity. } + dsLayeredFaded, + { The moved column or row is not displayed, behavior of original TCustomGrid + but line has red color. } + dsLine, + { The moved column or row is not displayed, behavior of original TCustomGrid. } + dsXORLine + ); + + { Declares possible values for the State parameter in the + @link(TKGridDrawCellEvent) event handler or @link(TKGridCell.DrawCell) method. } + TKGridDrawStateMembers = ( + { The cell has input focus and is currently edited. This is always 1 cell + that correspond to @link(TKCustomGrid.Col) and @link(TKCustomGrid.Row) + properties. Painting of the cell is automatically invoked to allow e.g. + background filling for inplace editors that don't fill the entire cell area. } + gdEdited, + { The cell is in the fixed region of the grid. } + gdFixed, + { The cell has input focus. This is always 1 cell that correspond to + @link(TKCustomGrid.Col) and @link(TKCustomGrid.Row) properties. } + gdFocused, + { Left mouse button is pressed. Cell repainting + is automatically invoked when mouse cursor is over the cell and the left + button is pressed. The cell is repainter if mouse button is released, either. } + gdMouseDown, + { Mouse cursor is over the cell in @link(goMouseOverCells) mode. Cell repainting + is automatically invoked when mouse cursor enters or leaves the cell. + Furthermore, if @link(TKCustomGrid.EditorMode) is True, the inplace editor will + be invalidated to allow proper editor underpainting, either. } + gdMouseOver, + { The cell is currently selected. This includes all cells that appear with + different default background color in either @link(goRangeSelect) or + @link(goRowSelect) mode. } + gdSelected, + { The cell belongs to the sorted column or row. } + gdSorted, + { Applies to the left most fixed column (if any). + The cell should paint visual shape like arrow to indicate that the + columns are sorted from lowest to highest value, like 'A' to 'Z'. } + gdColsSortedUp, + { Applies to the left most fixed column (if any). + The cell should paint visual shape like arrow to indicate that the + columns are sorted from highest to lowest value, like 'Z' to 'A'. } + gdColsSortedDown, + { Applies to the top most fixed row (if any). + The cell should paint visual shape like arrow to indicate that the + rows are sorted from lowest to highest value, like 'A' to 'Z'. } + gdRowsSortedUp, + { Applies to the top most fixed row (if any). + The cell should paint visual shape like arrow to indicate that the + rows are sorted from highest to lowest value, like 'Z' to 'A'. } + gdRowsSortedDown + ); + + { Set type for @link(TKGridDrawStateMembers) enumeration. } + TKGridDrawState = set of TKGridDrawStateMembers; + + { Declares possible values for the @link(TKCustomGrid.EditorTransparency) property. } + TKGridEditorTransparency = ( + { The grid decides which inplace editor should be treated as a transparent + control. This method works for all standard VCL controls. } + etDefault, + { Current inplace editor should be treated as opaque, i.e. not transparent. } + etNormal, + { Current inplace editor should be treated as transparent. } + etTransparent + ); + + { Method type for the Exchange parameter e.g. in the + @link(TKCustomGrid.InternalQuickSortNR) method. } + TKGridExchangeProc = procedure(Index1, Index2: Integer) of object; + + { Declares possible values for the InvisibleCells parameter in the + @link(TKCustomGrid.PointToCell) method. } + TKGridInvisibleCells = ( + { No invisible cells will be taken into account. Invisible cells are those + that are hidden (non-fixed) to the left or top. } + icNone, + { Invisible cells to the left will be taken into account at the expense of + the (possible) fixed cells. } + icFixedCols, + { Invisible cells to the top will be taken into account at the expense of + the (possible) fixed cells. } + icFixedRows, + { All invisible cells will be taken into account at the expense of + the (possible) fixed cells. } + icCells + ); + + { Declares a structure for hidden cell indicator glyphs. } + TKGridHCIBitmaps = record + HBegin, HCenter, HEnd, + VBegin, VCenter, VEnd: TKAlphaBitmap; + end; + + { Declares possible values for the @link(TKCustomGrid.Options) property. } + TKGridOption = ( + { Tries to put all columns to the visible area of the grid and omit free space + to the right of the last cell. No horizontal scrollbar appears. } + goAlignLastCol, + { Tries to put all rows to the visible area of the grid and omit free space + below the last cell. No vertical scrollbar appears. } + goAlignLastRow, + { The grid is locked into edit mode. The user does not need to use Enter or F2 + to turn on EditorMode everytime he moves to another cell. The behavior is + slightly different as in TCustomGrid. } + goAlwaysShowEditor, + { Enables the WM_ERASEBKGND message to be handled if True. This can be used + to avoid grid flickering for the case the grid is placed into a container + that requires repainting itself and all of its children after resizing. + This behavior is typical for nested TPanels. If you don't use these you + can set this option True to erase the background. The grid does not need + the background to be erased as it fills the entire client area through + WM_PAINT. But some users might need to erase the background due to the + strange behavior when activating an application by clicking the main form's + title bar. } + goEraseBackground, + { No painting is allowed beyond the cell outline. } + goClippedCells, + { Scrollable columns can be moved using the mouse. } + goColMoving, + { Scrollable columns can be individually resized. } + goColSizing, + { Scrollable columns can be sorted by mouse click at the first fixed row. The + sorted column is visually indicated by arrow at the first fixed row. } + goColSorting, + { Instructs the cell painter to draw each cell with double buffering to + avoid cell flickering. } + goDoubleBufferedCells, + { Selected cells are drawn with with a focus rectangle if the grid (not the + inplace editor) has the input focus. The behavior is slightly different + as in TCustomGrid. } + goDrawFocusSelected, + { Users can edit the contents of cells. No another limitation applicable. } + goEditing, + { If included, Enter does not turn on EditorMode, but causes another cell to + be focused. What cell it is depends on @link(TKCustomGrid.MoveDirection). } + goEnterMoves, + { Horizontal lines are drawn to separate the fixed (nonscrolling) rows + in the grid. } + goFixedHorzLine, + { Vertical lines are drawn to separate the fixed (nonscrolling) columns + in the grid. If @link(TKCustomGrid.ThemedCells) is True, these are not + drawn for fixed rows by default, as these are meant as a grid header. } + goFixedVertLine, + { Draws cells in the first fixed row in standard Win-API header style. } + goHeader, + { Terminates the first fixed row drawn in standard Win-API header style + by drawing a standard Win-API header terminator in an area not occupied by cells. } + goHeaderAlignment, + { Horizontal lines are drawn to separate the scrollable rows in the grid. } + goHorzLine, + { Hidden columns or rows are indicated in fixed cell area. } + goIndicateHiddenCells, + { Selection is indicated in the fixed cells by a specific color. } + goIndicateSelection, + { Columns or rows can be hidden with the mouse while being resized. Set to + False to enforce KGrid 1.2 behavior. } + goMouseCanHideCells, + { If included, then if the mouse enters or leaves a cell, these cells + will be invalidated and the cell under the mouse pointer gets a + @link(gdMouseOver) state. } + goMouseOverCells, + { If included, no text will be selected in the inplace editor upon its creation. + This applies only to inplace editors having a selectable text, of course. + The default behavior works only for editors responding to EM_SETSEL message. + For another editors, the behavior can be maintained by the + @link(TKCustomGrid.OnEditorSelect) event handler. } + goNoSelEditText, + { Users can select ranges of cells at one time. No another limitation applicable. } + goRangeSelect, + { Scrollable rows can be moved using the mouse. } + goRowMoving, + { Entire rows are selected rather than individual cells. No another limitation applicable. } + goRowSelect, + { Scrollable rows can be individually resized. Caution: Some inplace editors + cannot be resized in height - for example TComboBox. } + goRowSizing, + { Scrollable rows can be sorted by mouse click at the first fixed column. The + sorted row is visually indicated by arrow at the first fixed column. } + goRowSorting, + { Users can navigate through the cells in the grid using Tab and Shift+Tab. } + goTabs, + { Enables OS themes for both non-client and cells. } + goThemes, + { Enables OS themes for cells. } + goThemedCells, + { Vertical lines are drawn to separate the scrollable columns in the grid. } + goVertLine, + { If included, the grid becomes virtual grid. In this mode, data for the cells + must be supplied externally. No cell class instances are allocated. + @link(TKCustomGrid.Cell) property cannot be set and returns always nil. + @link(TKCustomGrid.Cells) property cannot be set and returns always empty string. + @link(TKCustomGrid.FCells) field is always nil - no grid structure is allocated. + Column and Row structures (@link(TKCustomGrid.FCols) and + @link(TKCustomGrid.FRows)) remain always allocated. } + goVirtualGrid + ); + + { Set type for @link(TKGridOption) enumeration. } + TKGridOptions = set of TKGridOption; + + { Declares possible values for the @link(TKCustomGrid.OptionsEx) property. } + TKGridOptionEx = ( + { When Inplace editor has horizontal constraint it will be horizontally centered. } + gxEditorHCenter, + { When Inplace editor has vertical constraint it will be vertically centered. } + gxEditorVCenter, + { Pressing Enter at the last cell appends a row. } + gxEnterAppendsRow, + { Pressing Enter wraps selection to next column/row. } + gxEnterWraps, + { Clicking fixed cells together with Shift key selects/unselects respective columns/rows. } + gxFixedCellClickSelect, + { All fixed cells will be painted with header theme (looks bad e.g. with classic WinXP). } + gxFixedThemedCells, + { Pressing TAB at the last cell appends a row. } + gxTabAppendsRow, + { Pressing TAB wraps selection to next column/row. } + gxTabWraps, + // aki: + { Allow edit fixed rows} + gxEditFixedRows, + { Allow edit fixed cols} + gxEditFixedCols + ); + + { Set type for @link(TKGridOptionEx) enumeration. } + TKGridOptionsEx = set of TKGridOptionEx; + + { Declares possible values for the Priority parameter in the @link(TKCustomGrid.MeasureCell) method. } + TKGridMeasureCellPriority = ( + { Row height stays, column width is adjusted. } + mpColWidth, + { Column width stays, row height is adjusted. } + mpRowHeight, + { Default cell extent adjustment. } + mpCellExtent + ); + + { Declares possible values for the Command parameter in the @link(TKCustomGrid.InternalMove) method. } + TKGridMoveCommand = ( + { No command. } + mcNone, + { Move to last row. } + mcBottom, + { Move to next row. } + mcDown, + { Move to last column. } + mcEnd, + { Move to first column. } + mcHome, + { Move to previous column. } + mcLeft, + { Move to bottom row on current page. } + mcMoveDown, + { Move to top row on current page. } + mcMoveUp, + { Move to next vertical page. } + mcPageDown, + { Move to next horizontal page. } + mcPageLeft, + { Move to previous horizontal page. } + mcPageRight, + { Move to previous vertical page. } + mcPageUp, + { Move to next column. } + mcRight, + { Move to first row. } + mcTop, + { Move to previous row. } + mcUp + ); + + { Declares possible values for the @link(TKCustomGrid.MoveDirection) property. } + TKGridMoveDirection = ( + { By pressing Enter, the cell below the currently focused cell will be focused. } + mdDown, + { By pressing Enter, the cell to the left of the currently focused cell will be focused. } + mdLeft, + { By pressing Enter, the cell to the right of the currently focused cell will be focused. } + mdRight, + { By pressing Enter, the cell above the currently focused cell will be focused. } + mdUp + ); + + { Declares possible values for the @link(TKCustomGrid.RangeSelectStyle) property. } + TKGridRangeSelectStyle = ( + { The focused cell is not the base cell and expands the selection. } + rsDefault, + { The focused cell is the base cell and does not expand the selection. } + rsMS_Excel + ); + + { @abstract(Declares the type e.g. for the @link(TKCustomGrid.Selection) property) + Declares the type for grid rectangle. A grid rectangle is a structure of + two independent grid points. +
    + Members: +
  • Col1, Row1, Col2, Row2 - rectangle of grid cells given by indexes.
  • +
  • Cell1, Cell2 - rectangle of grid cells given e.g. by top-left and bottom-right cells.
  • +
} + TKGridRect = record + case Integer of + 0: (Col1, Row1, Col2, Row2: Integer); + 1: (Cell1, Cell2: TKGridCoord); + end; + + { Declares possible values for the @link(TKCustomGrid.ScrollModeHorz) and @link(TKCustomGrid.ScrollModeVert) properties. } + TKGridScrollMode = ( + { The trackbar scrolls per pixel. } + smSmooth, + { The trackbar scrolls per cell. } + smCell + ); + + { Declares possible values for the Stage parameter in the @link(TKGridSelectionExpandEvent) + event handler or @link(TKCustomGrid.SelectionMove) method. } + TKGridSelectionStage = ( + { The selection moves entirely - the selection base cell changes. } + ssInit, + { The selection expands - the selection base cell remains unchanged. } + ssExpand + ); + + { Declares possible values for the Flags parameter in the + @link(TKCustomGrid.SelectionMove) method. } + TKGridSelectionFlag = ( + { Do not call the @link(TKCustomGrid.SelectCell) method. } + sfDontCallSelectCell, + { Force invalidation of the old and new selection. } + sfMustUpdate, + { Force calling of the @link(TKCustomGrid.ClampInView) method. } + sfClampInView, + { Do not set @link(TKCustomGrid.FMemCol) and @link(TKCustomGrid.FMemRow) fields. } + sfNoMemPos + ); + + { Set type for @link(TKGridSelectionFlag) enumeration. } + TKGridSelectionFlags = set of TKGridSelectionFlag; + + { Declares possible values for the Change parameter in the + @link(TKGridSizeChangedEvent) event handler. } + TKGridSizeChange = ( + { Columns have been deleted. } + scColDeleted, + { Columns have been inserted. } + scColInserted, + { Rows have been deleted. } + scRowDeleted, + { Rows have been inserted. } + scRowInserted + ); + + { Declares possible values for the @link(TKCustomGrid.SizingStyle) property. } + TKGridSizingStyle = ( + { Column widths or row heights update after the mouse button is released. + Old TCustomGrid behavior but line has red color. } + ssLine, + { Column widths or row heights update immediately. } + ssUpdate, + { Column widths or row heights update after the mouse button is released. + Old TCustomGrid behavior. } + ssXORLine + ); + + { Declares possible values for the @link(TKGridAxisItem.SortMode) property. } + TKGridSortMode = ( + { Corresponding column or row is not sorted. } + smNone, + { Corresponding column or row is sorted from lowest to highest value. } + smDown, + { Corresponding column or row is sorted from highest to lowest value. } + smUp + ); + + { Declares possible values for the @link(TKCustomGrid.SortStyle) property. } + TKGridSortStyle = ( + { First click sorts from lowest to highest value, second click sorts from highest to lowest value. } + ssDownUp, + { First click sorts from lowest to highest value, second click sorts from highest to lowest value, third click turns sorting off. } + ssDownUpNone, + { First click sorts from highest to lowest value, second click sorts from lowest to highest value, third click turns sorting off. } + ssUpDownNone + ); + + { Declares possible values for the @link(TKCustomGrid.FGridState) field. } + TKGridState = ( + { The mouse button has been pressed on a fixed cell that triggers + mouse click event. } + gsClickWaiting, + { The mouse button has been pressed on a fixed cell that triggers + column dragging. } + gsColMoveWaiting, + { The user is dragging a column to a new position. } + gsColMoving, + { The user is changing the width of a column. } + gsColSizing, + { The mouse button has been pressed on a fixed cell that triggers + column sorting. } + gsColSortWaiting, + { The grid layout is not changing. } + gsNormal, + { The mouse button has been pressed on a fixed cell that triggers + row dragging. } + gsRowMoveWaiting, + { The user is dragging a row to a new position. } + gsRowMoving, + { The user is changing the height of a row. } + gsRowSizing, + { The mouse button has been pressed on a fixed cell that triggers + row sorting. } + gsRowSortWaiting, + { The user is selecting a cell or row. } + gsSelecting + ); + + { @abstract(Declares event handler e.g. for the @link(TKCustomGrid.OnBeginColDrag) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • Origin - row or column index where dragging should be started.
  • +
  • MousePt - position of mouse cursor.
  • +
  • CanBeginDrag - True by default to allow the dragging to be started.
  • +
} + TKGridBeginDragEvent = procedure(Sender: TObject; var Origin: Integer; + const MousePt: TPoint; var CanBeginDrag: Boolean) of object; + + { @abstract(Declares event handler e.g. for the @link(TKCustomGrid.OnBeginColSizing) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • Index - index of a row or column that should be resized.
  • +
  • Pos - position of the sizing line + (even if it actually doesn't exist in @link(ssUpdate) sizing mode).
  • +
  • CanBeginSizing - True by default to allow the sizing to be started.
  • +
} + TKGridBeginSizingEvent = procedure(Sender: TObject; var Index, Pos: Integer; + var CanBeginSizing: Boolean) of object; + + { @abstract(Declares event handler for any cell notification events) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • ACol, ARow - column and row indexes of the corresponding cell.
  • +
} + TKGridCellEvent = procedure(Sender: TObject; ACol, ARow: Integer) of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnMouseCellHint) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • ACol, ARow - column and row indexes of the corresponding cell.
  • +
  • AShow - True if hint should be displayed, otherwise False.
  • +
} + TKGridCellHintEvent = procedure(Sender: TObject; ACol, ARow: Integer; AShow: Boolean) of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnCellSpan) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • ACol, ARow - column and row indexes of the cell whose span data is to be retrieved.
  • +
  • Span - resulting span data for that cell.
  • +
} + TKGridCellSpanEvent = procedure(Sender: TObject; ACol, ARow: Integer; var Span: TKGridCellSpan) of object; + + { @abstract(Declares event handler e.g. for the @link(TKCustomGrid.OnCheckColDrag) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • Origin - row or column index where dragging was started.
  • +
  • Destination - row or column index where dragging is about to end at this moment.
  • +
  • MousePt - position of mouse cursor.
  • +
  • CanDrop - True by default to allow the dropping to Destination.
  • +
} + TKGridCheckDragEvent = procedure(Sender: TObject; Origin: Integer; + var Destination: Integer; const MousePt: TPoint; var CanDrop: Boolean) of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnCompareCells)) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • Col1 - column index of the first cell or @link(cInvalidIndex) - + see @link(TKCustomGrid.InsertSortedCol).
  • +
  • Row1 - row index of the first cell or @link(cInvalidIndex) - + see @link(TKCustomGrid.InsertSortedRow).
  • +
  • Col2 - column index of the second cell.
  • +
  • Row2 - row index of the second cell.
  • +
+
    + Returns: +
  • Negative value (<0) if the value of the first cell is lower than + the value of the second cell.
  • +
  • Positive value (>0) if the value of the first cell is greater than + the value of the second cell.
  • +
  • Zero if values of both cells are the same.
  • +
} + TKGridCompareCellsEvent = function(Sender: TObject; Col1, Row1, Col2, Row2: Integer): + Integer of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnCustomSortCols) or + @link(TKCustomGrid.OnCustomSortRows) events) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • ByIndex - column or row index to sort rows or columns by.
  • +
  • SortMode - the sorting mode to sort rows or columns.
  • +
  • Sorted - set to True to avoid default sorting to be called.
  • +
} + TKGridCustomSortEvent = procedure(Sender: TObject; ByIndex: Integer; + SortMode: TKGridSortMode; var Sorted: Boolean) of object; + + { @abstract(Declares event handler e.g. for the @link(TKCustomGrid.OnDrawCell) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • ACol, ARow - column and row indexes of the cell being drawn.
  • +
  • R - location of cell on the canvas.
  • +
  • State - indicates the state of the cell.
  • +
} + TKGridDrawCellEvent = procedure(Sender: TObject; ACol, ARow: Integer; + R: TRect; State: TKGridDrawState) of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnEditorCreate) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • ACol, ARow - column and row indexes of the focused cell that + is about to become edited cell.
  • +
  • AEditor - nil by default to indicate that no inplace editor is + wanted for the cell. Assign any TWinControl instance to this Parameter + to create a custom inplace editor for the cell. Always create new + instance because it is owned by the grid and destroyed automatically + if no longer needed.
  • +
} + TKGridEditorCreateEvent = procedure(Sender: TObject; ACol, ARow: Integer; + var AEditor: TWinControl) of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnEditorDataFromGrid) + or @link(TKCustomGrid.OnEditorDataToGrid) events) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • AEditor - identifies the inplace editor.
  • +
  • ACol, ARow - column and row indexes of the edited cell.
  • +
  • AssignText - Allows to automatically set the cell text + to or from inplace editor. Set to False to disable this behavior.
  • +
} + TKGridEditorDataEvent = procedure(Sender: TObject; AEditor: TWinControl; + ACol, ARow: Integer; var AssignText: Boolean) of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnEditorDestroy) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • AEditor - identifies the inplace editor.
  • +
  • ACol, ARow - column and row indexes of the edited cell.
  • +
} + TKGridEditorDestroyEvent = procedure(Sender: TObject; var AEditor: TWinControl; + ACol, ARow: Integer) of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnEditorKeyPreview) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • AEditor - identifies the inplace editor.
  • +
  • ACol, ARow - column and row indexes of the edited cell.
  • +
  • Key - key code as passed to OnKeyDown, can be modified.
  • +
  • Shift - state of the control keys as passed to OnKeyDown.
  • +
  • IsGridKey - True by default to indicate that the key will be handled + by the grid. Set to False to let the inplace editor handle the key.
  • +
} + TKGridEditorKeyPreviewEvent = procedure(Sender: TObject; AEditor: TWinControl; + ACol, ARow: Integer; var Key: Word; Shift: TShiftState; var IsGridKey: Boolean) of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnEditorResize) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • AEditor - identifies the inplace editor.
  • +
  • ACol, ARow - column and row indexes of the edited cell.
  • +
  • ARect - initial bounding rectangle of the inplace editor. + You can modify it in order to place the editor somewhere else within the cell. + The inplace editor is always clipped within the cell.
  • +
} + TKGridEditorResizeEvent = procedure(Sender: TObject; AEditor: TWinControl; + ACol, ARow: Integer; var ARect: TRect) of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnEditorSelect) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • AEditor - identifies the inplace editor.
  • +
  • ACol, ARow - column and row indexes of the edited cell.
  • +
  • SelectAll - all the text should be selected in the inplace editor.
  • +
  • CaretToLeft - caret should be positioned to the left.
  • +
  • SelectedByMouse - the cell has been selected by mouse.
  • +
} + TKGridEditorSelectEvent = procedure(Sender: TObject; AEditor: TWinControl; + ACol, ARow: Integer; SelectAll, CaretToLeft, SelectedByMouse: Boolean) of object; + + { @abstract(Declares event handler e.g. for the @link(TKCustomGrid.OnEndColDrag) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • Origin - row or column index where dragging was started.
  • +
  • Destination - row or column index where dragging ends.
  • +
  • MousePt - position of mouse cursor.
  • +
  • CanEndDrag - True by default to allow the dragging to be ended.
  • +
} + TKGridEndDragEvent = procedure(Sender: TObject; Origin: Integer; + Destination: Integer; const MousePt: TPoint; var CanEndDrag: Boolean) of object; + + { @abstract(Declares event handler e.g. for the @link(TKCustomGrid.OnEndColSizing) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • Index - index of a row or column that is being resized.
  • +
  • Pos - current position of the sizing line + (even if it actually doesn't exist in @link(ssUpdate) sizing mode).
  • +
  • CanEndSizing - True by default to allow the resizing to be ended.
  • +
} + TKGridEndSizingEvent = procedure(Sender: TObject; Index, Pos: Integer; + var CanEndSizing: Boolean) of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnExchangeCols) or + @link(TKCustomGrid.OnExchangeRows) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • Index1 - index of the first column or row.
  • +
  • Index2 - index of the second column or row.
  • +
} + TKGridExchangeEvent = procedure(Sender: TObject; + Index1, Index2: Integer) of object; + + { @abstract(Declares event handler for any cell extent notification events) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • AIndex - column or row index.
  • +
} + TKGridExtentEvent = procedure(Sender: TObject; AIndex: Integer) of object; + + { @abstract(Declares event handler e.g. for the @link(TKCustomGrid.OnMeasureCell) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • ACol, ARow - column and row indexes of the cell being drawn.
  • +
  • R - location of cell on the canvas.
  • +
  • State - indicates the state of the cell.
  • +
  • Priority - specifies the cell measurement priority.
  • +
  • Extent - returns calculated cell extent.
  • +
} + TKGridMeasureCellEvent = procedure(Sender: TObject; ACol, ARow: Integer; + R: TRect; State: TKGridDrawState; Priority: TKGridMeasureCellPriority; + var Extent: TPoint) of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnColumnMoved) or + @link(TKCustomGrid.OnRowMoved) events) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • FromIndex - initial position of the column or row being moved.
  • +
  • ToIndex - final position of the column or row being moved.
  • +
} + TKGridMovedEvent = procedure(Sender: TObject; FromIndex, ToIndex: Integer) of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnSizeChanged) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • Change - identifies the change type.
  • +
  • At - index where column(s) or row(s) have been inserted or deleted.
  • +
  • Count - number of column(s) or row(s) that have been inserted or deleted.
  • +
} + TKGridSizeChangedEvent = procedure(Sender: TObject; + Change: TKGridSizeChange; At, Count: Integer) of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnSelectCell) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • ACol, ARow - column and row indexes of the cell that is about to be selected.
  • +
  • CanSelect - True by default to indicate that the cell can be selected. + Set to False to inhibit selecting of this cell.
  • +
} + TKGridSelectCellEvent = procedure(Sender: TObject; ACol, ARow: Integer; + var CanSelect: Boolean) of object; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnSelectCell) event) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • ACol, ARow - column and row indexes of the cell that is about to + expand the current selection.
  • +
  • CanExpand - True by default to indicate that the cell + can the selection. Set to False to inhibit further selection expanding.
  • +
} + TKGridSelectionExpandEvent = procedure(Sender: TObject; ACol, ARow: Integer; + var CanExpand: Boolean) of object; + +const + { Constant for invalid column or row indexes. Currently, it is used internally. + Functions @link(TKCustomGrid.InitialCol) and @link(TKCustomGrid.InitialRow) + return this value in case of invalid parameters. } + cInvalidIndex = -1; + + { This constant can be passed into the FirstCol or FirstRow parameter of the + @link(TKCustomGrid.UpdateAxes) method. } + cAll = -1; + + { Default value for the @link(TKCustomGrid.ColCount) property. } + cColCountDef = 5; + + { Default value for the @link(TKCustomGrid.DefaultColWidth) property. } + cDefaultColWidthDef = 64; + + { Default value for the @link(TKCustomGrid.DefaultRowHeight) property. } + cDefaultRowHeightDef = 21; + + { Default value for the @link(TKCustomGrid.DisabledDrawStyle) property. } + cDisabledDrawStyleDef = ddBright; + + { Default value for the @link(TKCustomGrid.DragStyle) property. } + cDragStyleDef = dsLayeredFaded; + + { Default value for the @link(TKCustomGrid.EditorTransparency) property. } + cEditorTransparencyDef = etDefault; + + { Default value for the @link(TKCustomGrid.FixedCols) property. } + cFixedColsDef = 1; + + { Default value for the @link(TKCustomGrid.FixedRows) property. } + cFixedRowsDef = 1; + + { Default value for the @link(TKCustomGrid.GridLineWidth) property. } + cGridLineWidthDef = 1; + + { Minimum value for the @link(TKCustomGrid.MinColWidth) property. } + cMinColWidthMin = 5; + { Default value for the @link(TKCustomGrid.MinColWidth) property. } + cMinColWidthDef = 10; + + { Minimum value for the @link(TKCustomGrid.MinRowHeight) property. } + cMinRowHeightMin = 5; + { Default value for the @link(TKCustomGrid.MinRowHeight) property. } + cMinRowHeightDef = 10; + + { Minimum value for the @link(TKCustomGrid.MouseCellHintTime) property. } + cMouseCellHintTimeMin = 100; + { Maximum value for the @link(TKCustomGrid.MouseCellHintTime) property. } + cMouseCellHintTimeMax = 10000; + { Default value for the @link(TKCustomGrid.MouseCellHintTime) property. } + cMouseCellHintTimeDef = 800; + + { Default value for the @link(TKCustomGrid.MoveDirection) property. } + cMoveDirectionDef = mdRight; + + { Default value for the @link(TKCustomGrid.Options) property. } + cOptionsDef = [goAlwaysShowEditor, goDrawFocusSelected, + goEnterMoves, goFixedVertLine, goFixedHorzLine, goIndicateHiddenCells, + goHeader, goHeaderAlignment, goHorzLine, goMouseCanHideCells, + goMouseOverCells, goRangeSelect, goThemes, goThemedCells, goVertLine]; + + { Default value for the @link(TKCustomGrid.OptionsEx) property. } + cOptionsExDef = [gxEnterWraps, gxTABWraps]; + + { Default value for the @link(TKCustomGrid.RangeSelectStyle) property. } + cRangeSelectStyleDef = rsDefault; + + { Default value for the @link(TKCustomGrid.RowCount) property. } + cRowCountDef = 5; + + { Default value for the @link(TKCustomGrid.ScrollBars) property. } + cScrollBarsDef = ssBoth; + + { Minimum value for the @link(TKCustomGrid.ScrollSpeed) property. } + cScrollSpeedMin = 50; + { Maximum value for the @link(TKCustomGrid.ScrollSpeed) property. } + cScrollSpeedMax = 1000; + { Default value for the @link(TKCustomGrid.ScrollSpeed) property. } + cScrollSpeedDef = 100; + + { Default value for the @link(TKCustomGrid.ScrollModeHorz) and @link(TKCustomGrid.ScrollModeVert) properties. } + cScrollModeDef = smSmooth; + + { Default value for the @link(TKCustomGrid.SizingStyle) property. } + cSizingStyleDef = ssUpdate; + + { Default value for the @link(TKCustomGrid.SortStyle) property. } + cSortStyleDef = ssDownUp; + + { Default value for the @link(TKGridColors.CellBkGnd) color property. } + cCellBkGndDef = clWindow; + { Default value for the @link(TKGridColors.CellLines) color property. } + cCellLinesDef = clBtnFace; + { Default value for the @link(TKGridColors.CellText) color property. } + cCellTextDef = clWindowText; + { Default value for the @link(TKGridColors.DragSuggestionBkGnd) color property. } + cDragSuggestionBkGndDef = clLime; + { Default value for the @link(TKGridColors.DragSuggestionLine) color property. } + cDragSuggestionLineDef = clBlack; + { Default value for the @link(TKGridColors.FixedCellBkGnd) color property. } + cFixedCellBkGndDef = clBtnFace; + { Default value for the @link(TKGridColors.FixedCellIndication) color property. } + cFixedCellIndicationDef = clCream; + { Default value for the @link(TKGridColors.FixedCellLines) color property. } + cFixedCellLinesDef = clWindowText; + { Default value for the @link(TKGridColors.FixedCellText) color property. } + cFixedCellTextDef = clBtnText; + { Default value for the @link(TKGridColors.FixedThemedCellLines) color property. } + cFixedThemedCellLinesDef = {$IFDEF USE_WINAPI}clBtnShadow{$ELSE}clWindowText{$ENDIF}; + { Default value for the @link(TKGridColors.FixedThemedCellHighlight) color property. } + cFixedThemedCellHighlightDef = clBtnHighlight; + { Default value for the @link(TKGridColors.FixedThemedCellShadow) color property. } + cFixedThemedCellShadowDef = clBtnFace; + { Default value for the @link(TKGridColors.FocusedCellBkGnd) color property. } + cFocusedCellBkGndDef = clHighlight; + { Default value for the @link(TKGridColors.FocusedCellText) color property. } + cFocusedCellTextDef = clHighlightText; + { Default value for the @link(TKGridColors.FocusedRangeBkgnd) color property. } + cFocusedRangeBkGndDef = clHighlight; // to be brigtened + { Default value for the @link(TKGridColors.FocusedRangeText) color property. } + cFocusedRangeTextDef = clHighlightText; + { Default value for the @link(TKGridColors.SelectedCellBkGnd) color property. } + cSelectedCellBkGndDef = clBtnFace; + { Default value for the @link(TKGridColors.SelectedCellText) color property. } + cSelectedCellTextDef = clBtnText; + { Default value for the @link(TKGridColors.SelectedRangeBkGnd) color property. } + cSelectedRangeBkGndDef = clBtnFace; // to be brigtened + { Default value for the @link(TKGridColors.SelectedRangeText) color property. } + cSelectedRangeTextDef = clBtnText; + // aki: + { Default value for then @link(TKGridColors.SelectedFixedCell) color property. } + cSelectedFixedCellBkGndDef = clCream; + { Index for the @link(TKGridColors.CellBkGnd) property. } + ciCellBkGnd = TKGridColorIndex(0); + { Index for the @link(TKGridColors.CellLines) property. } + ciCellLines = TKGridColorIndex(1); + { Index for the @link(TKGridColors.CellText) property. } + ciCellText = TKGridColorIndex(2); + { Index for the @link(TKGridColors.DragSuggestionBkGnd) property. } + ciDragSuggestionBkGnd = TKGridColorIndex(3); + { Index for the @link(TKGridColors.DragSuggestionLine) property. } + ciDragSuggestionLine = TKGridColorIndex(4); + { Index for the @link(TKGridColors.FixedCellBkGnd) property. } + ciFixedCellBkGnd = TKGridColorIndex(5); + { Index for the @link(TKGridColors.FixedCellIndication) property. } + ciFixedCellIndication = TKGridColorIndex(6); + { Index for the @link(TKGridColors.FixedCellLines) property. } + ciFixedCellLines = TKGridColorIndex(7); + { Index for the @link(TKGridColors.FixedCellText) property. } + ciFixedCellText = TKGridColorIndex(8); + { Index for the @link(TKGridColors.FixedThemedCellLines) property. } + ciFixedThemedCellLines = TKGridColorIndex(9); + { Index for the @link(TKGridColors.FixedThemedCellHighlight) property. } + ciFixedThemedCellHighlight = TKGridColorIndex(10); + { Index for the @link(TKGridColors.FixedThemedCellShadow) property. } + ciFixedThemedCellShadow = TKGridColorIndex(11); + { Index for the @link(TKGridColors.FocusedCellBkGnd) property. } + ciFocusedCellBkGnd = TKGridColorIndex(12); + { Index for the @link(TKGridColors.FocusedCellText) property. } + ciFocusedCellText = TKGridColorIndex(13); + { Index for the @link(TKGridColors.FocusedRangeBkGnd) property. } + ciFocusedRangeBkGnd = TKGridColorIndex(14); + { Index for the @link(TKGridColors.FocusedRangeText) property. } + ciFocusedRangeText = TKGridColorIndex(15); + { Index for the @link(TKGridColors.SelectedCellBkGnd) property. } + ciSelectedCellBkGnd = TKGridColorIndex(16); + { Index for the @link(TKGridColors.SelectedCellText) property. } + ciSelectedCellText = TKGridColorIndex(17); + { Index for the @link(TKGridColors.SelectedRangeBkGnd) property. } + ciSelectedRangeBkGnd = TKGridColorIndex(18); + { Index for the @link(TKGridColors.SelectedRangeText) property. } + ciSelectedRangeText = TKGridColorIndex(19); + // aki: + { Index for the @link(TKGridColors.SelectedFixedCell) property. } + ciSelectedFixedCellBkGnd = TKGridColorIndex(20); + // aki: + { Maximum color array index } + ciGridColorsMax = ciSelectedFixedCellBkGnd; + + { This internal flag is set if caret should be moved to the left side of the inplace editor. } + cGF_CaretToLeft = $00000001; + { This internal flag is set if the Set.. methods in @link(TKGridAxisItem) and + @link(TKGridCell) and their descendants must not call any grid methods that + could cause infinite recursion. } + cGF_GridUpdates = $00000002; + { This internal flag is set to allow column or row sizing at design time. } + cGF_DesignHitTest = $00000004; + { This internal flag is set to prevent recursive calls while inplace editor is being updated. } + cGF_EditorUpdating = $00000008; + { This internal flag is set to remember inplace editor state if the grid + has no input focus. } + cGF_EditorModeActive = $00000010; + { This internal flag is set if a cell is selected by mouse click. } + cGF_SelectedByMouse = $00000020; + { This internal flag is set if a cell is 'through-clicked'. } + cGF_ThroughClick = $00000040; + { This internal flag is set if a selectable grid area contains at least 1 merged cell. } + cGF_SelCellsMerged = $00000080; + { This internal flag is set if enter key has been pressed and handled by the grid. } + cGF_EnterPressed = $00000100; + +type + TKCustomGrid = class; + TKGridCell = class; + + { @abstract(Declares event handler for the @link(TKCustomGrid.OnCompareCellInstances)) +
    + Parameters: +
  • Sender - identifies the event caller.
  • +
  • Cell1 - pointer to the first cell
  • +
  • Cell2 - pointer to the second cell
  • +
+
    + Returns: +
  • Negative value (<0) if the value of the first cell is lower than + the value of the second cell.
  • +
  • Positive value (>0) if the value of the first cell is greater than + the value of the second cell.
  • +
  • Zero if values of both cells are the same.
  • +
} + TKGridCompareCellInstancesEvent = function(Sender: TObject; Cell1, Cell2: TKGridCell): + Integer of object; + + { @abstract(Base class to store column or row properties) + This is the base class for storing column or row properties. + It implements properties and methods that are common for columns and rows. } + TKGridAxisItem = class(TObject) + private + FCanResize: Boolean; + FExtent: Integer; + FGrid: TKCustomGrid; + FInitialPos: Integer; + FMaxExtent: Integer; + FMinExtent: Integer; + FSortArrowIndex: Integer; + FSortMode: TKGridSortMode; + FTag: TObject; + procedure SetMaxExtent(AValue: Integer); + procedure SetMinExtent(AValue: Integer); + protected + FBackExtent: Integer; + { Cell class aware version of @link(TKCustomGrid.OnBeginColDrag) or @link(TKCustomGrid.OnBeginRowDrag) + events. See the @link(TKGridBeginDragEvent) type for parameter interpretation. } + procedure BeginDrag(var Origin: Integer; const MousePt: TPoint; + var CanBeginDrag: Boolean); virtual; + { Cell class aware version of @link(TKCustomGrid.OnCheckColDrag) or @link(TKCustomGrid.OnCheckRowDrag) + events. See the @link(TKGridCheckDragEvent) type for parameter interpretation. } + procedure CheckDrag(Origin: Integer; var Destination: Integer; + const MousePt: TPoint; var CanDrop: Boolean); virtual; + { Cell class aware version of @link(TKCustomGrid.OnEndColDrag) or @link(TKCustomGrid.OnEndRowDrag) + events. See the @link(TKGridEndDragEvent) type for parameter interpretation. } + procedure EndDrag(Origin, Destination: Integer; const MousePt: TPoint; + var CanEndDrag: Boolean); virtual; + { Read method for the @link(TKGridAxisItem.Objects) property. Without implementation. } + function GetObjects(Index: Integer): TObject; virtual; abstract; + { Read method for the @link(TKGridAxisItem.Strings) property. Without implementation. } + function GetStrings(Index: Integer): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; virtual; abstract; + { Read method for the @link(TKGridAxisItem.Visible) property. Without implementation. } + function GetVisible: Boolean; virtual; + { Write method for the @link(TKGridAxisItem.Extent) property. Without implementation. } + procedure SetExtent(const Value: Integer); virtual; abstract; + { Write method for the @link(TKGridAxisItem.Objects) property. Without implementation. } + procedure SetObjects(Index: Integer; const Value: TObject); virtual; abstract; + { Write method for the @link(TKGridAxisItem.SortArrowIndex) property. Without implementation. } + procedure SetSortArrowIndex(Value: Integer); virtual; abstract; + { Write method for the @link(TKGridAxisItem.SortMode) property. Without implementation. } + procedure SetSortMode(const Value: TKGridSortMode); virtual; abstract; + { Write method for the @link(TKGridAxisItem.Strings) property. Without implementation. } + procedure SetStrings(Index: Integer; const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); virtual; abstract; + { Write method for the @link(TKGridAxisItem.Visible) property. Without implementation. } + procedure SetVisible(Value: Boolean); virtual; abstract; + public + { Creates the instance. Do not create custom instances. All necessary + TKGridAxisItem instances are created automatically by TKCustomGrid. } + constructor Create(AGrid: TKCustomGrid); virtual; + { Copies shareable properties of another TKGridAxisItem instances into this + TKGridAxisItem instance. } + procedure Assign(Source: TKGridAxisItem); overload; virtual; + { Makes it possible to assign a list of strings contained in TStrings + to the grid. This method is provided to retain compatibility with + TStringGrid. It behaves exactly the same way as the corresponding method + in TStringGrid. Without implementation. } + procedure Assign(Source: TStrings); overload; virtual; abstract; +{$IFDEF TKGRID_USE_JCL} + { Makes it possible to assign a list of strings contained in TWideStrings + to the grid. Without implementation. } + procedure Assign(Source: TWideStrings); overload; virtual; abstract; +{$ENDIF} + { Abstract prototype. Sets text of all cells corresponding to this column or row to empty string. } + procedure Clear; virtual; abstract; + { Returns True if shareable properties of this TKGridAxisItem instance have + the same value as those in Item. } + function {$ifdef COMPILER12_UP}EqualProperties{$ELSE}Equals{$ENDIF}(Item: TKGridAxisItem): Boolean; virtual; + { Shareable property. Determines if this column or row can be resized. + This property virtually covers the @link(TKCustomGrid.OnBeginColSizing) or + @link(TKCustomGrid.OnBeginRowSizing) events. } + property CanResize: Boolean read FCanResize write FCanResize; + { Shareable property. Determines the column width or row height. + Do not write this property unless you write a TKCustomGrid descendant. } + property Extent: Integer read FExtent write SetExtent; + { Pointer to the grid. You will probably need it when implementing application + specific behavior. } + property Grid: TKCustomgrid read FGrid; + { Non-shareable property. Determines the initial column or row position + just after it was inserted into the grid. Do not write this property + unless you write a TKCustomGrid descendant. } + property InitialPos: Integer read FInitialPos write FInitialPos; + { Specifies the maximum extent of this column or row. Set zero to disable check. + Does not work (cannot work) in goAlignLast... mode. } + property MaxExtent: Integer read FMaxExtent write SetMaxExtent; + { Specifies the minimum extent of this column or row. Set zero to disable check. + This setting overrides the @link(TKCustomGrid.MinColWidth) or + @link(TKCustomGrid.MinRowHeight) setting. } + property MinExtent: Integer read FMinExtent write SetMinExtent; + { Provides access to the object cell instances corresponding to the column or + row referred by this TKGridAxisItem instance. Provided to retain compatibility + with TStringGrid. } + property Objects[Index: Integer]: TObject read GetObjects write SetObjects; + { Specifies the index of the fixed column or row where the sorting can be + initiated/changed by mouse click and where the sorting arrow will be displayed. + This applies only for multiline column or row headers, i.e. if there are + two or more fixed columns or rows defined. } + property SortArrowIndex: Integer read FSortArrowIndex write SetSortArrowIndex; + { Makes it possible to sort column or row referred by this TKGridAxisItem + instance. } + property SortMode: TKGridSortMode read FSortMode write SetSortMode; + { Provides access to the obj cell instances corresponding to the column or + row referred by this TKGridAxisItem instance. } + property Strings[Index: Integer]: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF} read GetStrings write SetStrings; default; + { Shareable property. Determines if the column or row is visible. } + property Visible: Boolean read GetVisible write SetVisible; + { Provides access to custom object for Row } + property Tag: TObject read FTag write FTag; + end; + + { @abstract(Metaclass for @link(TKGridAxisItem)) This type is used internally. } + TKGridAxisItemClass = class of TKGridAxisItem; + + { @abstract(Dynamic array type to store @link(TKGridAxisItem) instances) + There are always two arrays of this type in TKCustomGrid. First of them + stores column properties - @link(TKCustomGrid.FCols) - and the second stores + row properties - @link(TKCustomGrid.FRows). } + TKGridAxisItems = array of TKGridAxisItem; + + { @abstract(Class to store column properties) + This class implements properties and methods specific to columns. } + TKGridCol = class(TKGridAxisItem) + private + FCellHint: Boolean; + FTabStop: Boolean; + function FindCol(out Index: Integer): Boolean; + protected + { Read method for the @link(TKGridAxisItem.Objects) property. Implementation for columns. } + function GetObjects(Index: Integer): TObject; override; + { Read method for the @link(TKGridAxisItem.Strings) property. Implementation for columns. } + function GetStrings(Index: Integer): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; override; + { Write method for the @link(TKGridAxisItem.Extent) property. Implementation for columns. } + procedure SetExtent(const Value: Integer); override; + { Write method for the @link(TKGridAxisItem.Objects) property. Implementation for columns. } + procedure SetObjects(Index: Integer; const Value: TObject); override; + { Write method for the @link(TKGridAxisItem.SortArrowIndex) property. Implementation for columns. } + procedure SetSortArrowIndex(Value: Integer); override; + { Write method for the @link(TKGridAxisItem.SortMode) property. Implementation for columns. } + procedure SetSortMode(const Value: TKGridSortMode); override; + { Write method for the @link(TKGridAxisItem.Strings) property. Implementation for columns. } + procedure SetStrings(Index: Integer; const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); override; + { Write method for the @link(TKGridAxisItem.Visible) property. Implementation for columns. } + procedure SetVisible(Value: Boolean); override; + public + { Creates the instance. Do not create custom instances. All necessary + TKGridCol instances are created automatically by TKCustomGrid. } + constructor Create(AGrid: TKCustomGrid); override; + { Copies the properties of another TKGridAxisItem instances into this + TKGridCol instance. } + procedure Assign(Source: TKGridAxisItem); override; + { Makes it possible to assign a list of strings contained in TStrings + to the grid. It behaves exactly the same way as the corresponding method + in TStringGrid. Implementation for columns, i.e. the strings contained + in Source are copied to the text cells corresponding to the column + referred by this TKGridCol instance. } + procedure Assign(Source: TStrings); override; +{$IFDEF TKGRID_USE_JCL} + { Makes it possible to assign a list of strings contained in TWideStrings + to the grid. Implementation for columns, i.e. the strings contained + in Source are copied to the text cells corresponding to the column + referred by this TKGridCol instance. } + procedure Assign(Source: TWideStrings); override; +{$ENDIF} + { Sets text of all cells corresponding to this column to empty string. } + procedure Clear; override; + { Returns True if shareable properties of this TKGridAxisItem instance have + the same value as those in Item. } + function {$ifdef COMPILER12_UP}EqualProperties{$ELSE}Equals{$ENDIF}(Item: TKGridAxisItem): Boolean; override; + { Shareable property. Determines if cell hint is enabled for this column. } + property CellHint: Boolean read FCellHint write FCellHint; + { Shareable property. Determines if pressing the TAB or Shift+TAB key can + move the input focus at a cell that belongs to this column. This property + has effect only if goTabs is present under @link(TKCustomGrid.Options). } + property TabStop: Boolean read FTabStop write FTabStop; + end; + + { @abstract(Metaclass for @link(TKGridCol)) This type is used in + @link(TKCustomGrid.ColClass) property. } + TKGridColClass = class of TKGridCol; + + { @abstract(Class to store row properties) + This class implements properties and methods specific to rows. } + TKGridRow = class(TKGridAxisItem) + private + function FindRow(out Index: Integer): Boolean; + protected + { Read method for the @link(TKGridAxisItem.Objects) property. Implementation for rows. } + function GetObjects(Index: Integer): TObject; override; + { Read method for the @link(TKGridAxisItem.Strings) property. Implementation for rows. } + function GetStrings(Index: Integer): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; override; + { Write method for the @link(TKGridAxisItem.Extent) property. Implementation for rows. } + procedure SetExtent(const Value: Integer); override; + { Write method for the @link(TKGridAxisItem.Objects) property. Implementation for rows. } + procedure SetObjects(Index: Integer; const Value: TObject); override; + { Write method for the @link(TKGridAxisItem.SortArrowIndex) property. Implementation for rows. } + procedure SetSortArrowIndex(Value: Integer); override; + { Write method for the @link(TKGridAxisItem.SortMode) property. Implementation for rows. } + procedure SetSortMode(const Value: TKGridSortMode); override; + { Write method for the @link(TKGridAxisItem.Strings) property. Implementation for rows. } + procedure SetStrings(Index: Integer; const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); override; + { Write method for the @link(TKGridAxisItem.Visible) property. Implementation for rows. } + procedure SetVisible(Value: Boolean); override; + public + { Creates the instance. Do not create custom instances. All necessary + TKGridRow instances are created automatically by TKCustomGrid. } + constructor Create(AGrid: TKCustomGrid); override; + { Sets text of all cells corresponding to this row to empty string. } + procedure Clear; override; + { Makes it possible to assign a list of strings contained in TStrings + to the grid. It behaves exactly the same way as the corresponding method + in TStringGrid. Implementation for rows, i.e. the strings contained + in Source are copied to the text cells corresponding to the row + referred by this TKGridRow instance. } + procedure Assign(Source: TStrings); override; +{$IFDEF TKGRID_USE_JCL} + { Makes it possible to assign a list of strings contained in TWideStrings + to the grid. Implementation for rows, i.e. the strings contained + in Source are copied to the text cells corresponding to the row + referred by this TKGridRow instance. } + procedure Assign(Source: TWideStrings); override; +{$ENDIF} + end; + + { @abstract(Metaclass for @link(TKGridRow)) This type is used in + @link(TKCustomGrid.RowClass) property. } + TKGridRowClass = class of TKGridRow; + + { @abstract(Base class to store cell properties) + This class implements properties and methods common to all cell classes. } + TKGridCell = class(TObject) + private + FGrid: TKCustomGrid; + FSpan: TKGridCellSpan; + procedure SetColSpan(const Value: Integer); + procedure SetRowSpan(const Value: Integer); + procedure SetSpan(const Value: TKGridCellSpan); + protected + { Called after specific property has been updated. Default behavioor: + Searches the cell in the parent grid and invalidates the cell. You can + override this method to extend behavior. } + procedure AfterUpdate; virtual; // formerly UpdateCell + { Called before specific property is to be updated. } + procedure BeforeUpdate; virtual; + { Cell class aware version of @link(TKCustomGrid.OnDrawCell). + Fills ARect with predefined Brush. } + procedure DrawCell(ACol, ARow: Integer; const ARect: TRect; + State: TKGridDrawState); virtual; + { Cell class aware version of @link(TKCustomGrid.OnEditorCreate). + The TKGridCell's implementation calls @link(TKCustomGrid.DefaultEditorCreate). } + procedure EditorCreate(ACol, ARow: Integer; var AEditor: TWinControl); virtual; + { Cell class aware version of @link(TKCustomGrid.OnEditorDataFromGrid). + The TKGridCell's implementation calls @link(TKCustomGrid.DefaultEditorDataFromGrid). } + procedure EditorDataFromGrid(AEditor: TWinControl; ACol, ARow: Integer; + var AssignText: Boolean); virtual; + { Cell class aware version of @link(TKCustomGrid.OnEditorDataToGrid). + The TKGridCell's implementation calls @link(TKCustomGrid.DefaultEditorDataToGrid). } + procedure EditorDataToGrid(AEditor: TWinControl; ACol, ARow: Integer; + var AssignText: Boolean); virtual; + { Cell class aware version of @link(TKCustomGrid.OnEditorDestroy). + The TKGridCell's implementation calls @link(TKCustomGrid.DefaultEditorDestroy). } + procedure EditorDestroy(var AEditor: TWinControl; ACol, ARow: Integer); virtual; + { Cell class aware version of @link(TKCustomGrid.OnEditorKeyPreview). + The TKGridCell's implementation calls @link(TKCustomGrid.DefaultEditorKeyPreview). } + procedure EditorKeyPreview(AEditor: TWinControl; ACol, ARow: Integer; + var Key: Word; Shift: TShiftState; var IsGridKey: Boolean); virtual; + { Cell class aware version of @link(TKCustomGrid.OnEditorResize). + The TKGridCell's implementation calls @link(TKCustomGrid.DefaultEditorResize). } + procedure EditorResize(AEditor: TWinControl; ACol, ARow: Integer; + var ARect: TRect); virtual; + { Cell class aware version of @link(TKCustomGrid.OnEditorSelect). + The TKGridCell's implementation calls @link(TKCustomGrid.DefaultEditorSelect). } + procedure EditorSelect(AEditor: TWinControl; ACol, ARow: Integer; + SelectAll, CaretToLeft, SelectedByMouse: Boolean); virtual; + { Searches the cell in the parent grid. } + function FindCell(out ACol, ARow: Integer): Boolean; virtual; + { Initializes the cell data. } + procedure Initialize; virtual; + { Cell class aware version of @link(TKCustomGrid.OnMeasureCell). } + procedure MeasureCell(ACol, ARow: Integer; const ARect: TRect; + State: TKGridDrawState; Priority: TKGridMeasureCellPriority; + var Extent: TPoint); virtual; + { Cell class aware version of @link(TKCustomGrid.OnSelectCell). + The TKGridCell's implementation does nothing. } + procedure SelectCell(ACol, ARow: Integer; var ACanSelect: Boolean); + virtual; + { Cell class aware version of @link(TKCustomGrid.OnSelectionExpand). + The TKGridCell's implementation does nothing. } + procedure SelectionExpand(ACol, ARow: Integer; var ACanExpand: Boolean); virtual; + public + { Creates the instance. You can create a custom instance and pass it + e.g. to a @link(TKCustomGrid.Cell) property. The AGrid parameter has no meaning + in this case and you may set it to nil. } + constructor Create(AGrid: TKCustomGrid); virtual; + { Applies TKGridCell properties to the cell painter. + The TKGridCell's implementation does nothing. } + procedure ApplyDrawProperties; virtual; + { Copies the properties of another TKGridCell instances into this + TKGridCell instance. } + procedure Assign(Source: TKGridCell); virtual; + { Clears the cell data. } + procedure Clear; + { Specifies the number of columns the cell should be spanned to. } + property ColSpan: Integer read FSpan.ColSpan write SetColSpan; + { Pointer to the grid. You will probably need it when implementing application + specific behavior. } + property Grid: TKCustomgrid read FGrid; + { Specifies the number of rows the cell should be spanned to. } + property RowSpan: Integer read FSpan.RowSpan write SetRowSpan; + { Specifies both cell span parameters. } + property Span: TKGridCellSpan read FSpan write SetSpan; + end; + + { @abstract(Metaclass for @link(TKGridCell)) This type is used in the + @link(TKCustomGrid.CellClass) property. } + TKGridCellClass = class of TKGridCell; + + { @abstract(Dynamic array type to store row of @link(TKGridCell) instances) + This one-dimensional array stores cell properties. } + TKGridCellRow = array of TKGridCell; + + { @abstract(Dynamic array type to store the entire grid of @link(TKGridCell) instances) + This two-dimensional array stores cell properties - @link(TKCustomGrid.FCells). } + TKGridCells = array of TKGridCellRow; + + { @abstract(Class for simple textual cell) + This cell class implements properties and methods needed to display/edit a cell + with simple text. } + TKGridTextCell = class(TKGridCell) + private + {$IFDEF STRING_IS_UNICODE} + FText: string; + function GetTextPtr: PChar; + {$ELSE} + FText: PWideChar; // WideString is slow as storage here + function GetText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; + {$ENDIF} + procedure SetText(const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); + protected + { Assigns a new text string into this TKGridTextCell instance. The new + string will be assigned by a grow on demand method, i.e. the memory + allocated for the string can only grow within each assignment. It continues + to grow until the TKGridTextCell instance is destroyed. } + procedure AssignText(const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); virtual; + { Cell class aware version of @link(TKCustomGrid.OnEditorCreate). + Creates a TEdit inplace editor. } + procedure EditorCreate(ACol, ARow: Integer; var AEditor: TWinControl); override; + { Initializes the cell data. } + procedure Initialize; override; + public + { Creates the instance. See @link(TKGridCell.Create) for details. } + constructor Create(AGrid: TKCustomGrid); override; + { Destroys the instance. See TObject.Destroy in Delphi help. } + destructor Destroy; override; + { Applies TKGridTextCell properties to the cell painter. } + procedure ApplyDrawProperties; override; + { Copies shareable properties of another instance that inherits from + TKGridCell into this TKGridTextCell instance. } + procedure Assign(Source: TKGridCell); override; + { Readonly property. This is the editable text that appears in the cell - + published as pointer for fast read operations like sorting. } + property TextPtr: {$IFDEF STRING_IS_UNICODE}PChar{$ELSE}PWideChar{$ENDIF} read {$IFDEF STRING_IS_UNICODE}GetTextPtr{$ELSE}FText{$ENDIF}; + { Shareable property. This is the editable text that appears in the cell. } + property Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF} read {$IFDEF STRING_IS_UNICODE}FText{$ELSE}GetText{$ENDIF} write SetText; + end; + + { @abstract(Class for a textual cell with custom appearance) + This cell class implements properties and methods needed to display/edit + a textual cell with custom appearance. } + TKGridAttrTextCell = class(TKGridTextCell) + private + FAttributes: TKTextAttributes; + FBackColor: TColor; + FBrush: TBrush; + FBrushChanged: Boolean; + FFont: TFont; + FFontChanged: Boolean; + FHAlign: TKHAlign; + FHPadding: Integer; + FVAlign: TKVAlign; + FVPadding: Integer; + procedure SetAttributes(const AValue: TKTextAttributes); + procedure SetFHAlign(const Value: TKHAlign); + procedure SetFHPadding(const Value: Integer); + procedure SetFVAlign(const Value: TKVAlign); + procedure SetFVPadding(const Value: Integer); + procedure SetBackColor(const Value: TColor); + protected + { Called from FFont.OnChange. Sets FontChanged to True. } + procedure FontChange(Sender: TObject); + { Called from FBrush.OnChange. Sets BrushChanged to True. } + procedure BrushChange(Sender: TObject); + { Initializes the cell data. } + procedure Initialize; override; + public + { Creates the instance. See @link(TKGridCell.Create) for details. } + constructor Create(AGrid: TKCustomGrid); override; + { Destroys the instance. See TObject.Destroy in Delphi help. } + destructor Destroy; override; + { Applies TKGridAttrTextCell properties to the cell painter. } + procedure ApplyDrawProperties; override; + { Copies shareable properties of another instance that inherits from + TKGridCell into this TKGridAttrTextCell instance. } + procedure Assign(Source: TKGridCell); override; + { Shareable property. These are the text attributes to render the text. } + property Attributes: TKTextAttributes read FAttributes write SetAttributes; + { Shareable property. This is the color used to fill the gaps between + a non solid @link(TKGridAttrTextCell.Brush). } + property BackColor: TColor read FBackColor write SetBackColor; + { Shareable property. This is the brush that will be used to fill the cell background. } + property Brush: TBrush read FBrush; + { Non-shareable property. Returns True if Brush.OnChange occured. } + property BrushChanged: Boolean read FBrushChanged; + { Shareable property. This is the font that will be used to render the text. } + property Font: TFont read FFont; + { Non-shareable property. Returns True if Font.OnChange occured. } + property FontChanged: Boolean read FFontChanged; + { Shareable property. This is the horizontal alignment + that will be used to place the text within the cell rectangle. } + property HAlign: TKHAlign read FHAlign write SetFHAlign; + { Shareable property. This is the horizontal padding + of the text from the cell rectangle. } + property HPadding: Integer read FHPadding write SetFHPadding; + { Shareable property. This is the vertical alignment + that will be used to place the text within the cell rectangle. } + property VAlign: TKVAlign read FVAlign write SetFVAlign; + { Shareable property. This is the vertical padding + of the text from the cell rectangle. } + property VPadding: Integer read FVPadding write SetFVPadding; + end; + +{$IFDEF TKGRIDOBJECTCELL_IS_TKGRIDATTRTEXTCELL} + { @exclude } + TKGridObjectCellAncestor = TKGridAttrTextCell; +{$ELSE} + {$IFDEF TKGRIDOBJECTCELL_IS_TKGRIDTEXTCELL} + { @exclude } + TKGridObjectCellAncestor = TKGridTextCell; + {$ELSE} + { @exclude } + TKGridObjectCellAncestor = TKGridCell; + {$ENDIF} +{$ENDIF} + + { @abstract(Class for an object cell) + This cell class implements properties and methods needed to store a custom + object in a cell. This class is implemented for backward compatibility + with TStringGrid. You can implement different cell classes to store any user + defined data. } + TKGridObjectCell = class(TKGridObjectCellAncestor) + private + FCellObject: TObject; + procedure SetCellObject(Value: TObject); + protected + { Initializes the cell data. } + procedure Initialize; override; + public + { Creates the instance. See @link(TKGridCell.Create) for details. } + constructor Create(AGrid: TKCustomGrid); override; + { Destroys the instance. See TObject.Destroy in Delphi help. } + destructor Destroy; override; + { Copies shareable properties of another instance that inherits from + TKGridCell into this TKGridObjectCell instance. } + procedure Assign(Source: TKGridCell); override; + { Shareable property. This is the object stored within the cell class. + A single object instance passed to CellObject cannot be shared among multiple + cell class instances. The reason is that TObject instances do not support + Assign method, more convenient it would be to store TPersistents. } + property CellObject: TObject read FCellObject write SetCellObject; + end; + + { @abstract(Wrapper for a versatile and easily extensible cell painting engine) + Properties and methods of this class provide standard cell painting. + To adapt cell painting, you can use combinations of elementary painting + methods in the @link(TKCustomGrid.OnDrawCell) event handler or + override and adapt some high level methods of TKGridCellPainter. } + TKGridCellPainter = class(TObject) + private + FAttributes: TKTextAttributes; + FBackColor: TColor; + FBlockRect: TRect; + FButton: Boolean; + FButtonPressed: Boolean; + FCanvas: TCanvas; + FCheckBox: Boolean; + FCheckBoxHAlign: TKHAlign; + FCheckBoxHPadding: Integer; + FCheckboxState: TCheckBoxState; + FCheckBoxVAlign: TKVAlign; + FCheckBoxVPadding: Integer; + FCellPos: TPoint; + FCellRect: TRect; + FClipLock: Integer; + FCol: Integer; + FGraphic: TGraphic; + FGraphicDrawText: Boolean; + FGraphicHAlign: TKHAlign; + FGraphicHPadding: Integer; + FGraphicStretchMode: TKStretchMode; + FGraphicVAlign: TKVAlign; + FGraphicVPadding: Integer; + FGrid: TKCustomGrid; + FHotFrameOnly: Boolean; + FHAlign: TKHAlign; + FHPadding: Integer; + FRgn: HRGN; + FRow: Integer; + FSortArrow: TKAlphaBitmap; + FSortArrowHAlign: TKHAlign; + FSortArrowHPadding: Integer; + FState: TKGridDrawState; + FText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; + FValidClipping: Boolean; + FVAlign: TKVAlign; + FVPadding: Integer; + function GetCheckBoxChecked: Boolean; + procedure SetCheckBox(AValue: Boolean); + procedure SetCheckBoxChecked(const Value: Boolean); + protected + { Returns True if the grid is being printed out. } + FPrinting: Boolean; + { High level method. Provides default behavior needed to initialize painting + of a cell. It is called automatically in @link(TKCustomGrid.PaintCell). } + procedure BeginDraw; virtual; + { High level method. Provides default behavior needed to finalize painting + of a cell. It is called automatically in @link(TKCustomGrid.PaintCell). } + procedure EndDraw; virtual; + { Read method for the @link(TKGridCellPainter.SortArrowWidth) property. } + function GetSortArrowWidth: Integer; virtual; + { Initializes all canvas independent attributes to default values. Called + from DefaultAttributes just before cell painting. } + procedure Initialize; virtual; + public + { Creates the instance. Do not create custom instances. All necessary + TKGridCellPainter instances are created automatically by TKCustomGrid. } + constructor Create(AGrid: TKCustomGrid); + { Destroys the instance. See TObject.Destroy in Delphi help. } + destructor Destroy; override; + { Forces the drawing output to be clipped within @link(TKGridCellPainter.CellRect). + This behavior must be cancelled by @link(TKGridCellPainter.EndClip) when + no longer needed. You don't need to call BeginClip if the @link(TKCustomGrid.Options) + property already contains goClippedCells. } + function BeginClip: Boolean; virtual; + { Calculates the checkbox position within BaseRect, if any. The position + is stored in Bounds (checkbox with padding) and Interior (checkbox without + padding). Bounds are excluded from BaseRect. } + function CellCheckBoxRect(var BaseRect: TRect; out Bounds, Interior: TRect; StretchMode: TKStretchMode): Boolean; + { Calculates the graphic position within BaseRect, if any. The position + is stored in Bounds (graphic with padding) and Interior (graphic without + padding). Bounds are excluded from BaseRect. } + function CellGraphicRect(var BaseRect: TRect; out Bounds, Interior: TRect; StretchMode: TKStretchMode): Boolean; + { Calculates the sorting arrow position within BaseRect, if any. The position + is stored in Bounds (sorting arrow with padding) and Interior (sorting arrow + without padding). Bounds are excluded from BaseRect. } + function CellSortArrowRect(var BaseRect: TRect; out Bounds, Interior: TRect): Boolean; + { Calculates the cell text horizontal and vertical extent, if any. } + function CellTextExtent(const BaseRect: TRect; out Extent: TPoint): Boolean; + { Calculates the text position within BaseRect, if any. The position + is stored in Bounds (text with padding) and Interior (text without padding). + Bounds are excluded from BaseRect. } + function CellTextRect(var BaseRect: TRect; out Bounds, Interior: TRect): Boolean; + { Low level method. Prepares default painting attributes. Under current + implementation, DefaultAttributes applies default colors to the + @link(TKGridCellPainter.Canvas)'s Brush and Font properties. } + procedure DefaultAttributes; virtual; + { Highest level method. Provides default painting of any cell. You should call + DefaultDraw when implementing the @link(TKCustomGrid.OnDrawCell) event handler + unless any specific cell painting is required. This method supersedes + the obsolete @link(DefaultDrawCell) function. } + procedure DefaultDraw; virtual; + { Returns the combination of edge masks (BF_...) to paint a fixed cell + correctly in old TCustomGrid style or if no OS themes are available. } + function DefaultEdges: Cardinal; virtual; + { Highest level method. Provides default cell extent calculation. } + function DefaultMeasure(Priority: TKGridMeasureCellPriority): TPoint; virtual; + { Low level method. Paints common parts of a themed and non-themed cell. } + procedure DrawCellCommon; virtual; + { Low level method. Paints button frame. } + procedure DrawCellButton(Bounds: TRect); + { Low level method. Paints checkbox frame. } + procedure DrawCellCheckBox(const Bounds, Interior: TRect); + { Low level method. Paints the graphic (if any) within the rectangle specified by Interior. + Fills the rectangle specified by Bounds with current brush. } + procedure DrawCellGraphic(const Bounds, Interior: TRect); + { Low level method. Paints the sort arrow within the rectangle specified by Interior. + Fills the rectangle specified by Bounds with current brush. } + procedure DrawCellSortArrow(const Bounds, Interior: TRect); + { Low level method. Paints a button frame. } + procedure DrawButtonFrame(const ARect: TRect); virtual; + { Low level method. Paints a check box frame. } + procedure DrawCheckBoxFrame(const ARect: TRect); virtual; + { Low level method. Paints cell text. } + procedure DrawCellText(var ARect: TRect); virtual; + { Low level method. Paints a standard focus rectangle around the focused + cell. } + procedure DrawCellFocus(const ARect: TRect; SkipTest: Boolean = False); virtual; + { High level method. Paints an empty cell, i.e. only fills the cell background. } + procedure DrawEmptyCell; virtual; + { High level method. Paints a non themed fixed cell. } + procedure DrawFixedCell; virtual; + { Low level method. Paints fixed cell background. } + procedure DrawFixedCellBackground(const ARect: TRect); virtual; + { Low level method. Paints non-themed fixed cell background. } + procedure DrawFixedCellNonThemedBackground(const ARect: TRect); virtual; + { High level method. Paints a fixed cell in Windows Header style. } + procedure DrawHeaderCell; virtual; + { Low level method. Paints header background. } + procedure DrawHeaderCellBackground(const ARect: TRect); + { Low level method. Paints selection background frame. } + procedure DrawNormalCellBackground(const ARect: TRect); virtual; + { High level method. Paints a selectable cell. } + procedure DrawSelectableCell; virtual; + { Low level method. Paints selection background frame. } + procedure DrawSelectedCellBackground(const ARect: TRect; RClip: PRect = nil); virtual; + { High level method. Paints a themed fixed cell. } + procedure DrawThemedFixedCell; virtual; + { High level method. Paints a themed fixed cell in Windows Header style. } + procedure DrawThemedHeaderCell; virtual; + { Restores normal drawing output after previous + @link(TKGridCellPainter.BeginClip) call. } + procedure EndClip; virtual; + { Specifies the text attributes used to render the cell text. } + property Attributes: TKTextAttributes read FAttributes write FAttributes; + { Specifies the color used to fill the gaps if the Brush + referred by @link(TKGridCellPainter.Canvas) is not solid brush. } + property BackColor: TColor read FBackColor write FBackColor; + { Specifies the bounding rectangle of block of cells. This value can be given + either in TKCustomGrid's client coordinates or, in @link(goDoubleBufferedCells) + mode, relative to @link(TKGridCellPainter.CellPos). } + property BlockRect: TRect read FBlockRect write FBlockRect; + { Determines if a standard button frame should be painted for a selectable + cell. To paint a button frame, you need to implement the @link(OnDrawCell) + event handler, set Button to True and call @link(TKGridCellPainter.DefaultDraw), + which ensures correct painting of a button frame. } + property Button: Boolean read FButton write FButton; + { Specifies if the button frame should be painted in pressed or released (normal) + state. This property has no effect unless @link(TKGridCellPainter.Button) + is True. } + property ButtonChecked: Boolean read FButtonPressed write FButtonPressed; + { Identifies the Canvas where the cell will be painted to. The value of this + property is either equal to TKCustomGrid.@link(TKCustomGrid.Canvas) or, in + @link(goDoubleBufferedCells) mode, equal to a memory device context whose + dimensions correspond to the size of the cell. When implementing the + @link(OnDrawCell) event handler, you can paint to TKCustomGrid.Canvas as + usual in TStringGrid. However, if you wish to use goDoubleBufferedCells, + you must paint to TKGridCellPainter.Canvas. } + property Canvas: TCanvas read FCanvas write FCanvas; + { Determines if a standard check box frame should be painted for a selectable + cell. To paint a check box frame, you need to implement the @link(OnDrawCell) + event handler, set CheckBox to True and call @link(TKGridCellPainter.DefaultDraw), + which ensures correct painting of a check box frame. } + property CheckBox: Boolean read FCheckBox write SetCheckBox; + { Specifies if the check box frame should be painted in checked or unchecked + state. This property is for backward compatibility and has no effect unless + @link(TKGridCellPainter.CheckBox) is True. For new designs use the CheckBoxState property. } + property CheckBoxChecked: Boolean read GetCheckBoxChecked write SetCheckBoxChecked; + { Specifies the horizontal padding for the sorting arrow. } + property CheckBoxHAlign: TKHAlign read FCheckBoxHAlign write FCheckBoxHAlign; + { Specifies the horizontal padding for the sorting arrow. } + property CheckBoxHPadding: Integer read FCheckBoxHPadding write FCheckBoxHPadding; + { Specifies if the check box frame should be painted in checked, grayed + or unchecked state. This property has no effect unless + @link(TKGridCellPainter.CheckBox) is True. Added by Karol Schmidt } + property CheckboxState: TCheckBoxState read FCheckboxState write FCheckboxState; + { Specifies the vertical padding for the sorting arrow. } + property CheckBoxVAlign: TKVAlign read FCheckBoxVAlign write FCheckBoxVAlign; + { Specifies the vertical padding for the sorting arrow. } + property CheckBoxVPadding: Integer read FCheckBoxVPadding write FCheckBoxVPadding; + { Specifies the left and top position/origin of the cell in TKCustomGrid's client + coordinates. } + property CellPos: TPoint read FCellPos write FCellPos; + { Specifies the bounding rectangle of the cell. This value can be given + either in TKCustomGrid's client coordinates or, in @link(goDoubleBufferedCells) + mode, relative to @link(TKGridCellPainter.CellPos). } + property CellRect: TRect read FCellRect write FCellRect; + { Specifies the column index of the cell. } + property Col: Integer read FCol write FCol; + { Specifies the image that should be drawn in the cell. } + property Graphic: TGraphic read FGraphic write FGraphic; + { Specifies if the text should appear next to the image. } + property GraphicDrawText: Boolean read FGraphicDrawText write FGraphicDrawText; + { Specifies the horizontal alignment for the image. } + property GraphicHAlign: TKHAlign read FGraphicHAlign write FGraphicHAlign; + { Specifies the horizontal padding for the image. } + property GraphicHPadding: Integer read FGraphicHPadding write FGraphicHPadding; + { Specifies if the the image should be stretched within the cell (aspect ratio is preserved). } + property GraphicStretchMode: TKStretchMode read FGraphicStretchMode write FGraphicStretchMode; + { Specifies the vertical alignment for the image. } + property GraphicVAlign: TKVAlign read FGraphicVAlign write FGraphicVAlign; + { Specifies the vertical padding for the image. } + property GraphicVPadding: Integer read FGraphicVPadding write FGraphicVPadding; + { Specifies the calling grid. } + property Grid: TKCustomGrid read FGrid; + { This is the default horizontal alignment that will be used to place the text + within the cell rectangle. } + property HAlign: TKHAlign read FHAlign write FHAlign; + { When true, a check box frame etc. is only painted "hot" when mouse cursor is + over that frame. When false, it is painted "hot" when mouse cursor is over + entire cell. } + property HotFrameOnly: Boolean read FHotFrameOnly write FHotFrameOnly; + { This is the default horizontal padding for the text. } + property HPadding: Integer read FHPadding write FHPadding; + { Returns True if the grid is being printed out. Needed e.g. for font height + adjstment while printing. } + property Printing: Boolean read FPrinting; + { Specifies the row index of the cell. } + property Row: Integer read FRow write FRow; + { Returns the width of the sorting arrow glyph. This value can be either zero + if no sorting arrow should be drawn for the cell (most cases), or a width + of the glyph for column/row sorting. } + property SortArrowWidth: Integer read GetSortArrowWidth; + { Specifies the horizontal padding for the check box. } + property SortArrowHAlign: TKHAlign read FSortArrowHAlign write FSortArrowHAlign; + { Specifies the horizontal padding for the sorting arrow. } + property SortArrowHPadding: Integer read FSortArrowHPadding write FSortArrowHPadding; + { Specifies the draw state of the cell. } + property State: TKGridDrawState read FState write FState; + { Specifies the text that appears in the cell. } + property Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF} read FText write FText; + { This is the default vertical alignment that will be used to place the text + within the cell rectangle. } + property VAlign: TKVAlign read FVAlign write FVAlign; + { This is the default vertical padding for the text. } + property VPadding: Integer read FVPadding write FVPadding; + end; + + { @abstract(Metaclass for @link(TKGridCellPainter)) This type is used in the + @link(TKCustomGrid.CellPainterClass) property. } + TKGridCellPainterClass = class of TKGridCellPainter; + + { @abstract(Container for all colors used by @link(TKCustomGrid) class) + This container allows to group many colors into one item in object inspector. + Colors are accessible via published properties or several public Color* + properties. } + TKGridColors = class(TPersistent) + private + FGrid: TKCustomGrid; + FBrightRangeBkGnd: Boolean; + FColorScheme: TKGridColorScheme; + function GetColor(Index: TKGridColorIndex): TColor; + function GetColorEx(Index: TKGridColorIndex): TColor; + procedure SetColor(Index: TKGridColorIndex; Value: TColor); + procedure SetColorEx(Index: TKGridColorIndex; Value: TColor); + procedure SetColors(const Value: TKColorArray); + protected + FBrightColors: TKColorArray; + FColors: TKColorArray; + { Initializes the color array. } + procedure Initialize; virtual; + { Returns the specific color according to ColorScheme. } + function InternalGetColor(Index: TKGridColorIndex): TColor; virtual; + { Replaces the specific color. } + procedure InternalSetColor(Index: TKGridColorIndex; Value: TColor); virtual; + public + { Creates the instance. You can create a custom instance and pass it + e.g. to a @link(TKCustomGrid.Colors) property. The AGrid parameter has no meaning + in this case and you may set it to nil. } + constructor Create(AGrid: TKCustomGrid); + { Copies the properties of another instance that inherits from + TPersistent into this TKGridColors instance. } + procedure Assign(Source: TPersistent); override; + { Ensures cell range background colors will be brightened if specified by + @link(TKGridColors.BrightRangeBkGnd). } + procedure BrightRangeBkGnds; + { Clears cached brighter colors. } + procedure ClearBrightColors; + { Specifies color scheme for reading of published properties - see GetColor in source code} + property ColorScheme: TKGridColorScheme read FColorScheme write FColorScheme; + { Returns always normal color - regardless of the ColorScheme setting. } + property Color[Index: TKGridColorIndex]: TColor read GetColorEx write SetColorEx; + { Returns array of normal colors. } + property Colors: TKColorArray read FColors write SetColors; + published + { Specifies if cell range colors should be brightened from focused cell colors. } + property BrightRangeBkGnd: Boolean read FBrightRangeBkGnd write FBrightRangeBkGnd default True; + { Background color for non-fixed cells. } + property CellBkGnd: TColor index ciCellBkGnd read GetColor write SetColor default cCellBkGndDef; + { Color for lines around non-fixed cells. } + property CellLines: TColor index ciCellLines read GetColor write SetColor default cCellLinesDef; + { Text color for non-fixed cells. } + property CellText: TColor index ciCellText read GetColor write SetColor default cCellTextDef; + { Background color for drag suggestion stroke. } + property DragSuggestionBkGnd: TColor index ciDragSuggestionBkGnd read GetColor write SetColor default cDragSuggestionBkGndDef; + { Line color for drag suggestion stroke. } + property DragSuggestionLine: TColor index ciDragSuggestionLine read GetColor write SetColor default cDragSuggestionLineDef; + { Background color for fixed cells. } + property FixedCellBkGnd: TColor index ciFixedCellBkGnd read GetColor write SetColor default cFixedCellBkGndDef; + { Background color for fixed cells that currently indicate selection. } + property FixedCellIndication: TColor index ciFixedCellIndication read GetColor write SetColor default cFixedCellIndicationDef; + { Color for lines around fixed cells. } + property FixedCellLines: TColor index ciFixedCellLines read GetColor write SetColor default cFixedCellLinesDef; + { Text color for fixed cells. } + property FixedCellText: TColor index ciFixedCellText read GetColor write SetColor default cFixedCellTextDef; + { Color for lines around fixed cells if goThemedCells is True} + property FixedThemedCellLines: TColor index ciFixedThemedCellLines read GetColor write SetColor default cFixedThemedCellLinesDef; + { Color for 3D highlight effects for fixed cells if goThemedCells is True} + property FixedThemedCellHighlight: TColor index ciFixedThemedCellHighlight read GetColor write SetColor default cFixedThemedCellHighlightDef; + { Color for 3D shadow effects for fixed cells if goThemedCells is True} + property FixedThemedCellShadow: TColor index ciFixedThemedCellShadow read GetColor write SetColor default cFixedThemedCellShadowDef; + { Background color for focused cell defined by Selection.Cell1. } + property FocusedCellBkGnd: TColor index ciFocusedCellBkGnd read GetColor write SetColor default cFocusedCellBkGndDef; + { Text color for focused cell defined by Selection.Cell1. } + property FocusedCellText: TColor index ciFocusedCellText read GetColor write SetColor default cFocusedCellTextDef; + { Background color for another focused cells within the range or full row selection. } + property FocusedRangeBkGnd: TColor index ciFocusedRangeBkGnd read GetColor write SetColor default cFocusedRangeBkGndDef; + { Text color for another focused cells within the range or full row selection. } + property FocusedRangeText: TColor index ciFocusedRangeText read GetColor write SetColor default cFocusedRangeTextDef; + { Background color for selected cells defined by Selection.Cell1. } + property SelectedCellBkGnd: TColor index ciSelectedCellBkGnd read GetColor write SetColor default cSelectedCellBkGndDef; + { Text color for selected cells defined by Selection.Cell1. } + property SelectedCellText: TColor index ciSelectedCellText read GetColor write SetColor default cSelectedCellTextDef; + { Background color for another selected cells within the range or full row selection. } + property SelectedRangeBkGnd: TColor index ciSelectedRangeBkGnd read GetColor write SetColor default cSelectedRangeBkGndDef; + { Text color for another selected cells within the range or full row selection. } + property SelectedRangeText: TColor index ciSelectedRangeText read GetColor write SetColor default cSelectedRangeTextDef; + // aki: + { Background color for selected cells defined by Selection.Cell1. } + property SelectedFixedCellBkGnd: TColor index ciSelectedFixedCellBkGnd read GetColor write SetColor default cSelectedFixedCellBkGndDef; + end; + + { @abstract(KGrid base component) This is the class that you use + as the ancestor for your TKCustomGrid overrides. } + TKCustomGrid = class(TKCustomControl) + private + {$IFDEF FPC} + FFlat: Boolean; + {$ENDIF} + FCellClass: TKGridCellClass; + FCellPainter: TKGridCellPainter; + FCellPainterClass: TKGridCellPainterClass; + FColClass: TKGridColClass; + FColCount: Integer; + FDefaultColWidth: Integer; + FDefaultRowHeight: Integer; + FDisabledDrawStyle: TKGridDisabledDrawStyle; + FDragDest: Integer; + FDragOrigin: Integer; + FDragStyle: TKGridDragStyle; + FEditorTransparency: TKGridEditorTransparency; + FFixedCols: Integer; + FFixedRows: Integer; + FGridLineWidth: Integer; + FMinColWidth: Integer; + FMinRowHeight: Integer; + FMouseCellHintTime: Cardinal; + FMoveDirection: TKGridMoveDirection; + FOptions: TKGridOptions; + FOptionsEx: TKGridOptionsEx; + FRowClass: TKGridRowClass; + FRowCount: Integer; + FRangeSelectStyle: TKGridRangeSelectStyle; + FScrollBars: TScrollStyle; + FScrollModeVert: TKGridScrollMode; + FScrollModeHorz: TKGridScrollMode; + FScrollSpeed: Cardinal; + FScrollTimer: TTimer; + FSizingIndex: Integer; + FSizingDest: Integer; + FSizingStyle: TKGridSizingStyle; + FSortModeLock: Integer; + FSortStyle: TKGridSortStyle; + FThroughClick: Boolean; + FTopLeft: TKGridCoord; + FTopLeftExtent: TKGridCoord; + FOnBeginColDrag: TKGridBeginDragEvent; + FOnBeginColSizing: TKGridBeginSizingEvent; + FOnBeginRowDrag: TKGridBeginDragEvent; + FOnBeginRowSizing: TKGridBeginSizingEvent; + FOnCellSpan: TKGridCellSpanEvent; + FOnChanged: TKGridCellEvent; + FOnCheckColDrag: TKGridCheckDragEvent; + FOnCheckRowDrag: TKGridCheckDragEvent; + FOnColMoved: TKGridMovedEvent; + FOnColWidthsChanged: TNotifyEvent; + FOnColWidthsChangedEx: TKGridExtentEvent; + FOnCompareCellInstances: TKGridCompareCellInstancesEvent; + FOnCompareCells: TKGridCompareCellsEvent; + FOnCustomSortCols: TKGridCustomSortEvent; + FOnCustomSortRows: TKGridCustomSortEvent; + FOnDrawCell: TKGridDrawCellEvent; + FOnEditorCreate: TKGridEditorCreateEvent; + FOnEditorDataFromGrid: TKGridEditorDataEvent; + FOnEditorDataToGrid: TKGridEditorDataEvent; + FOnEditorDestroy: TKGridEditorDestroyEvent; + FOnEditorKeyPreview: TKGridEditorKeyPreviewEvent; + FOnEditorResize: TKGridEditorResizeEvent; + FOnEditorSelect: TKGridEditorSelectEvent; + FOnEndColDrag: TKGridEndDragEvent; + FOnEndColSizing: TKGridEndSizingEvent; + FOnEndRowDrag: TKGridEndDragEvent; + FOnEndRowSizing: TKGridEndSizingEvent; + FOnExchangeCols: TKGridExchangeEvent; + FOnExchangeRows: TKGridExchangeEvent; + FOnMeasureCell: TKGridMeasureCellEvent; + FOnMouseCellHint: TKGridCellHintEvent; + FOnMouseClickCell: TKGridCellEvent; + FOnMouseDblClickCell: TKGridCellEvent; + FOnMouseEnterCell: TKGridCellEvent; + FOnMouseLeaveCell: TKGridCellEvent; + FOnRowMoved: TKGridMovedEvent; + FOnRowHeightsChanged: TNotifyEvent; + FOnRowHeightsChangedEx: TKGridExtentEvent; + FOnSelectCell: TKGridSelectCellEvent; + FOnSelectionExpand: TKGridSelectionExpandEvent; + FOnSizeChanged: TKGridSizeChangedEvent; + FOnTopLeftChanged: TNotifyEvent; + function GetAllCellsSelected: Boolean; + function GetAllRowsSelected: Boolean; + function GetAllColsSelected: Boolean; + function GetCell(ACol, ARow: Integer): TKGridCell; + function GetCells(ACol, ARow: Integer): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; + function GetCellSpan(ACol, ARow: Integer): TKGridCellSpan; + function GetCols(Index: Integer): TKGridCol; + function GetColWidths(Index: Integer): Integer; + function GetDefaultDrawing: Boolean; + function GetEditorMode: Boolean; + function GetEffectiveColSpacing(ACol: Integer): Integer; + function GetEffectiveRowSpacing(ARow: Integer): Integer; + function GetEntireColSelected(Index: Integer): Boolean; + function GetEntireSelectedColCount: Integer; + function GetEntireRowSelected(Index: Integer): Boolean; + function GetEntireSelectedRowCount: Integer; + function GetGridHeight: Integer; + function GetGridWidth: Integer; + function GetLastVisibleCol: Integer; + function GetLastVisibleRow: Integer; + function GetMoreCellsSelected: Boolean; + function GetObjects(ACol, ARow: Integer): TObject; + function GetRowHeights(Index: Integer): Integer; + function GetRows(Index: Integer): TKGridRow; + function GetSelection: TKGridRect; + function GetSelectionCount: Integer; + function GetSelectionRect: TRect; + function GetSelections(Index: Integer): TKGridRect; + function GetSortCol: Integer; + function GetSortRow: Integer; + function GetTabStops(Index: Integer): Boolean; + function GetThemedCells: Boolean; + function GetThemes: Boolean; + function GetVisibleColCount: Integer; + function GetVisibleGridRect: TKGridRect; + function GetVisibleRowCount: Integer; + procedure ReadColWidths(Reader: TReader); + procedure ReadRowHeights(Reader: TReader); + {$IFDEF FPC} + procedure SetFlat(Value: Boolean); + {$ENDIF} + procedure SetCell(ACol, ARow: Integer; Value: TKGridCell); + procedure SetCellPainterClass(Value: TKGridCellPainterClass); + procedure SetCells(ACol, ARow: Integer; const Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); + procedure SetCellSpan(ACol, ARow: Integer; Value: TKGridCellSpan); + procedure SetCol(Value: Integer); + procedure SetColCount(Value: Integer); + procedure SetColors(Value: TKGridColors); + procedure SetColWidths(Index: Integer; Value: Integer); + procedure SetDefaultColWidth(Value: Integer); + procedure SetDefaultDrawing(Value: Boolean); + procedure SetDefaultRowHeight(Value: Integer); + procedure SetDisabledDrawStyle(Value: TKGridDisabledDrawStyle); + procedure SetDragStyle(Value: TKGridDragStyle); + procedure SetEditorMode(Value: Boolean); + procedure SetEditorTransparency(Value: TKGridEditorTransparency); + procedure SetFixedCols(Value: Integer); + procedure SetFixedRows(Value: Integer); + procedure SetGridLineWidth(Value: Integer); + procedure SetLeftCol(Value: Integer); + procedure SetMinColWidth(Value: Integer); + procedure SetMinRowHeight(Value: Integer); + procedure SetMouseCellHintTime(const AValue: Cardinal); + procedure SetObjects(ACol, ARow: Integer; Value: TObject); + procedure SetOptions(Value: TKGridOptions); + procedure SetOptionsEx(Value: TKGridOptionsEx); + procedure SetRow(Value: Integer); + procedure SetRowCount(Value: Integer); + procedure SetRowHeights(Index: Integer; Value: Integer); + procedure SetScrollBars(Value: TScrollStyle); + procedure SetScrollModeHorz(const Value: TKGridScrollMode); + procedure SetScrollModeVert(const Value: TKGridScrollMode); + procedure SetScrollSpeed(Value: Cardinal); + procedure SetSelection(const Value: TKGridRect); + procedure SetSelections(Index: Integer; const Value: TKGridRect); + procedure SetSizingStyle(Value: TKGridSizingStyle); + procedure SetTabStops(Index: Integer; Value: Boolean); + procedure SetTopRow(Value: Integer); + procedure WriteColWidths(Writer: TWriter); + procedure WriteRowHeights(Writer: TWriter); + procedure CMDesignHitTest(var Msg: TLMMouse); message CM_DESIGNHITTEST; + procedure CMEnabledChanged(var Msg: TLMessage); message CM_ENABLEDCHANGED; + procedure CMShowingChanged(var Msg: TLMessage); message CM_SHOWINGCHANGED; + procedure CMSysColorChange(var Msg: TLMessage); message CM_SYSCOLORCHANGE; + procedure CMVisibleChanged(var Msg: TLMessage); message CM_VISIBLECHANGED; + procedure CMWantSpecialKey(var Msg: TLMKey); message CM_WANTSPECIALKEY; + procedure WMChar(var Msg: TLMChar); message LM_CHAR; + procedure WMEraseBkGnd(var Msg: TLMEraseBkGnd); message LM_ERASEBKGND; + procedure WMGetDlgCode(var Msg: TLMNoParams); message LM_GETDLGCODE; + procedure WMHScroll(var Msg: TLMHScroll); message LM_HSCROLL; + procedure WMKillFocus(var Msg: TLMKillFocus); message LM_KILLFOCUS; + procedure WMSetFocus(var Msg: TLMSetFocus); message LM_SETFOCUS; + procedure WMVScroll(var Msg: TLMVScroll); message LM_VSCROLL; + protected + { Gains access to the cell hint timer. } + FCellHintTimer: TTimer; + { Two-dimensional dynamic array to store cell instances. Different cell + classes can be used for cell instances. } + FCells: TKGridCells; + { Provides direct access to the color class for TKCustomGrid descendants } + FColors: TKGridColors; + { Dynamic array to store column instances. Different column classes can + be used for column instances. } + FCols: TKGridAxisItems; + { Icon for column/row moving suggestion arrow. } + FDragArrow: TKAlphaBitmap; + { Wrapper for the window used to visually indicate a dragged column or row. + Under Win2K or later system, this is a layered window. Under Win98SE or older + system, it is a normal popup window. } + FDragWindow: TKDragWindow; + { Copy of the cell being currently edited. } + FEditedCell: TKGridCell; + { Provides direct access to the inplace editor instance for TKCustomGrid descendants. } + FEditor: TWinControl; + { Specifies the current bounding rectangle of inplace editor. } + FEditorRect: TRect; + { Specifies the current position of inplace editor. If @link(TKCustomGrid.Selection).Cell1 + is different from FEditorCell, the editor needs to be updated immediatelly + to make these two values equal again. } + FEditorCell: TKGridCoord; + { Pointer to the original WindowProc property of the inplace editor. } + FEditorWindowProc: TWndMethod; + { Holds the mutually exclusive grid state. } + FGridState: TKGridState; + { Glyphs for hidden cell indicators. } + FHCI: TKGridHCIBitmaps; + { Specifies the cell hint window. } + FHint: TKHintWindow; + { Specifies the cell where hint timer has been started. } + FHintCell: TKGridCoord; + { Specifies the cell where left mouse button has been pressed. } + FHitCell: TKGridCoord; + { Specifies the point where left mouse button has been pressed. } + FHitPos: TPoint; + { Field for @link(TKCustomGrid.MaxCol) property. Descendants can modify it. } + FMaxCol: Integer; + { Field for @link(TKCustomGrid.MaxRow) property. Descendants can modify it. } + FMaxRow: Integer; + { Field to remember current column position for keyboard commands. } + FMemCol: Integer; + { Field to remember current row position for keyboard commands. } + FMemRow: Integer; + { Specifies the cell where mouse is over. FMouseOver is valid if goMouseOverCells + is included in @link(TKCustomGrid.Options). } + FMouseOver: TKGridCoord; + { Dynamic array to store row instances. Different row classes can + be used for row instances. } + FRows: TKGridAxisItems; + { Specifies current(topmost) selection not affected by @link(goRowSelect) as + @link(TKCustomGrid.Selection). } + FSelection: TKGridRect; + { Specifies all selections except FSelection. This separation is done for + backward compatibility. } + FSelections: array of TKGridRect; + { Current scrolling position in pixels (bound to cell boundary). } + FScrollPos: TPoint; + { Current scrolling offset in pixels for smSmooth mode (relative to cell boundary). } + FScrollOffset: TPoint; + { Auxilliary bitmap for various tasks. } + FTmpBitmap: TBitmap; + {$IFDEF FPC} + { Temporary mouse cursor. } + FTmpCursor: TCursor; + {$ENDIF} + { Adjusts the page setup. Ensures the PrintingMapped property is always True. } + procedure AdjustPageSetup; override; + { Adjusts any selection rectangle specified by ASelection to be valid + selection in @link(goRowSelect) mode, i.e. makes ASelection to span + the entire row(s). } + function AdjustSelection(const ASelection: TKGridRect): TKGridRect; virtual; + { Calls @link(TKCustomGrid.OnBeginColDrag) event handler or column class aware equivalent. + See the @link(TKGridBeginDragEvent) type for parameter interpretation. } + function BeginColDrag(var Origin: Integer; const MousePt: TPoint): Boolean; virtual; + { Calls @link(TKCustomGrid.OnBeginColSizing) event handler or checks the + @link(TKGridAxisItem.CanResize) property to decide whether the column can + be resized. See the @link(TKGridBeginSizingEvent) type for parameter interpretation. } + function BeginColSizing(var Index, Pos: Integer): Boolean; virtual; + { Calls @link(TKCustomGrid.OnBeginRowDrag) event handler or row class aware equivalent. + See the @link(TKGridBeginDragEvent) type for parameter interpretation. } + function BeginRowDrag(var Origin: Integer; const MousePt: TPoint): Boolean; virtual; + { Calls @link(TKCustomGrid.OnBeginRowSizing) event handler or checks the + @link(TKGridAxisItem.CanResize) property to decide whether the row can + be resized. See the @link(TKGridBeginSizingEvent) type for parameter interpretation. } + function BeginRowSizing(var Index, Pos: Integer): Boolean; virtual; + { Cancels any dragging or resizing operations performed by mouse. } + procedure CancelMode; override; + { This method is called periodically from the cell hint timer. } + procedure CellHintTimerHandler(Sender: TObject); virtual; + { In a non virtual grid, this method is called after @link(TKCustomGrid.OnEditorDestroy) + if the cell content has been modified. Changed calls @link(TKCustomGrid.OnChanged) + event handler. } + procedure Changed; virtual; + { Modifies the size of @link(FCols), @link(FRows) and @link(FCells). Updates + @link(TKCustomGrid.FixedCols), @link(TKCustomGrid.ColCount), @link(TKCustomGrid.MaxCol), + @link(TKCustomGrid.FixedRows), @link(TKCustomGrid.RowCount), @link(TKCustomGrid.MaxRow). } + procedure ChangeDataSize(ColInsert: Boolean; ColAt, ColCnt: Integer; + RowInsert: Boolean; RowAt, RowCnt: Integer); virtual; + { Calls @link(TKCustomGrid.OnCheckColDrag) event handler or column class aware equivalent. + See the @link(TKGridCheckDragEvent) type for parameter interpretation. } + function CheckColDrag(Origin: Integer; var Destination: Integer; + const MousePt: TPoint): Boolean; virtual; + { Calls @link(TKCustomGrid.OnCheckRowDrag) event handler or row class aware equivalent. + See the @link(TKGridCheckDragEvent) type for parameter interpretation. } + function CheckRowDrag(Origin: Integer; var Destination: Integer; + const MousePt: TPoint): Boolean; virtual; + { Forces the scrollable cell specified by ACol and ARow to become visible. } + function ClampInView(ACol, ARow: Integer): Boolean; + { Calls @link(TKCustomGrid.OnColumnMoved) event handler. + See the @link(TKGridMovedEvent) type for parameter interpretation. } + procedure ColMoved(FromIndex, ToIndex: Integer); virtual; + { Calls @link(TKCustomGrid.OnColWidthsChanged) event handler. } + procedure ColWidthsChanged(ACol: Integer); virtual; + { Calls @link(TKCustomGrid.OnCompareCells) event handler for the given two cell instances. } + function CompareCellInstances(ACell1, ACell2: TKGridCell): Integer; virtual; + { Calls @link(TKCustomGrid.OnCompareCells) event handler for the given two cells. } + function CompareCells(ACol1, ARow1, ACol2, ARow2: Integer): Integer; virtual; + { Calls @link(TKCustomGrid.OnCompareCells) event handler for two cells + belonging to the same row identified by ARow. ACol1 and ACol2 are column + indexes of these two cells. Method is used to compare grid rows. } + function CompareCols(ARow, ACol1, ACol2: Integer): Integer; virtual; + { Calls @link(TKCustomGrid.OnCompareCells) event handler for two cells + belonging to the same column identified by ACol. ARow1 and ARow2 are row + indexes of these two cells. Method is used to compare grid columns. } + function CompareRows(ACol, ARow1, ARow2: Integer): Integer; virtual; + { Overriden method - see Delphi help. CreateParams defines additional styles + for the KGrid window (scrollbars etc.)} + procedure CreateParams(var Params: TCreateParams); override; + { Calls @link(TKCustomGrid.OnCustomSortCols) event handler. + See the @link(TKGridCustomSortEvent) type for parameter interpretation. } + function CustomSortCols(ByRow: Integer; var SortMode: TKGridSortMode): Boolean; virtual; + { Calls @link(TKCustomGrid.OnCustomSortRows) event handler. + See the @link(TKGridCustomSortEvent) type for parameter interpretation. } + function CustomSortRows(ByCol: Integer; var SortMode: TKGridSortMode): Boolean; virtual; + { Clears all user defined column widths. } + procedure DefaultColWidthChanged; virtual; + { Clears all user defined row heights. } + procedure DefaultRowHeightChanged; virtual; + { Provides default behavior for an inplace editor if it's caret should be + positioned to the left side. } + procedure DefaultSetCaretToLeft(Key: Word; ShiftState: TShiftState); virtual; + { Defines the custom properties for *.dfm streaming. } + procedure DefineProperties(Filer: TFiler); override; + { Overriden method - see Delphi help. Responds to mouse wheel events. } + function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override; + { Overriden method - see Delphi help. Responds to mouse wheel events. } + function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override; + { Updates column/row dragging state if mouse is moved or scrolling is initiated by mouse. + Called from @link(TKCustomGrid.MouseMove) and @link(TKCustomGrid.ScrollTimerHandler). } + procedure DragMove(ACol, ARow: Integer; MousePt: TPoint); + { Calls @link(TKCustomGrid.OnDrawCell) event handler or cell class aware equivalent. + See the @link(TKGridDrawCellEvent) type for parameter interpretation. } + function DrawCell(ACol, ARow: Integer; ARect: TRect; + AState: TKGridDrawState): Boolean; virtual; + { Calls @link(TKCustomGrid.OnEditorCreate) event handler or cell class aware equivalent. + See the @link(TKGridEditorCreateEvent) type for parameter interpretation. } + function EditorCreate(ACol, ARow: Integer): TWinControl; virtual; + { Calls @link(TKCustomGrid.OnEditorDataFromGrid) event handler or cell class aware equivalent. + See the @link(TKGridEditorDataEvent) type for parameter interpretation. } + procedure EditorDataFromGrid(AEditor: TWinControl; ACol, ARow: Integer); virtual; + { Calls @link(TKCustomGrid.OnEditorDataToGrid) event handler or cell class aware equivalent. + See the @link(TKGridEditorDataEvent) type for parameter interpretation. } + procedure EditorDataToGrid(AEditor: TWinControl; ACol, ARow: Integer); virtual; + { Calls @link(TKCustomGrid.OnEditorDestroy) event handler or cell class aware equivalent. + See the @link(TKGridEditorDestroyEvent) type for parameter interpretation. } + procedure EditorDestroy(var AEditor: TWinControl; ACol, ARow: Integer); virtual; + { Determines if the current inplace editor should be treated as transparent + control from the grid's point of view. @link(TKCustomGrid.EditorTransparency) + has higher priority than the default behavior implemented by this method. } + function EditorIsTransparent: Boolean; virtual; + { Calls @link(TKCustomGrid.OnEditorKeyPreview) event handler or cell class aware equivalent. + See the @link(TKGridEditorDataEvent) type for parameter interpretation. } + function EditorKeyPreview(AEditor: TWinControl; ACol, ARow: Integer; + var Key: Word; Shift: TShiftState): Boolean; virtual; + { Calls @link(TKCustomGrid.OnEditorResize) event handler or cell class aware equivalent. + See the @link(TKGridEditorResizeEvent) type for parameter interpretation. } + procedure EditorResize(AEditor: TWinControl; ACol, ARow: Integer; + var ARect: TRect); virtual; + { Calls @link(TKCustomGrid.OnEditorSelect) event handler or cell class aware equivalent. + See the @link(TKGridEditorSelectEvent) type for parameter interpretation. } + procedure EditorSelect(AEditor: TWinControl; ACol, ARow: Integer; + SelectAll, CaretToLeft, SelectedByMouse: Boolean); virtual; + { EditorWindowProc is the subclassed window procedure for inplace editor. } + procedure EditorWindowProc(var Msg: TLMessage); virtual; + { Calls @link(TKCustomGrid.OnEndColDrag) event handler or column class aware equivalent. + See the @link(TKGridEndDragEvent) type for parameter interpretation. } + function EndColDrag(Origin, Destination: Integer; + const MousePt: TPoint): Boolean; virtual; + { Calls @link(TKCustomGrid.OnEndColSizing) event handler. + See the @link(TKGridEndSizingEvent) type for parameter interpretation. } + function EndColSizing(var Index, Pos: Integer): Boolean; virtual; + { Calls @link(TKCustomGrid.OnEndRowDrag) event handler or row class aware equivalent. + See the @link(TKGridEndDragEvent) type for parameter interpretation. } + function EndRowDrag(Origin, Destination: Integer; + const MousePt: TPoint): Boolean; virtual; + { Calls @link(TKCustomGrid.OnEndRowSizing) event handler. + See the @link(TKGridEndSizingEvent) type for parameter interpretation. } + function EndRowSizing(var Index, Pos: Integer): Boolean; virtual; + { Destroys all column, row and cell instances. } + procedure FreeData; + { Returns information structure for column or row axis. Some fields of the + Info structure must be already defined before calling this function. + See @link(TKGridAxisInfo) for details. } + procedure GetAxisInfo(var Info: TKGridAxisInfo); virtual; + { Returns bounding rectangle where dragged column or row should appear. } + function GetDragRect(Info: TKGridAxisInfoBoth; out DragRect: TRect): Boolean; virtual; + { Returns the combination of invisible cells that must be taken into account + for the state indicated by GridState. } + function GridStateToInvisibleCells: TKGridInvisibleCells; + { Determines if the grid can have a horizontal scrollbar. } + function HasHorzScrollBar: Boolean; virtual; + { Determines if the grid can have a vertical scrollbar. } + function HasVertScrollBar: Boolean; virtual; + { Used internally to physically exchange two distinct columns. } + procedure InternalExchangeCols(Index1, Index2: Integer); virtual; + { Used internally to physically exchange two distinct rows. } + procedure InternalExchangeRows(Index1, Index2: Integer); virtual; + { Used internally to check if the given grid rectangle contains any merged cell areas + and if so, then expand it so that the result encloses all respective merged cells. } + function InternalExpandGridRect(const GridRect: TKGridRect): TKGridRect; virtual; + { Retrieves the base cell if the cell given by ACol and ARow belongs to a merged cell + or returns ACol and ARow if it is a non-merged cell. } + procedure InternalFindBaseCell(ACol, ARow: Integer; out BaseCol, BaseRow: Integer); virtual; + { Used internally to reverse the order of previously sorted rows or columns + in a fast manner, without cell comparisons. } + procedure InternalFlip(Left, Right: Integer; Exchange: TKGridExchangeProc); virtual; + { Used internally. Returns a cell instance for the cell identified by ACol and ARow. If the + cell instance is nil, creates a new instance for the cell using + @link(TKCustomGrid.CellClass). } + function InternalGetCell(ACol, ARow: Integer): TKGridCell; virtual; + { Returns the column span and row span for given cell. Does not perform cell validity check. } + function InternalGetCellSpan(ACol, ARow: Integer): TKGridCellSpan; virtual; + { Returns the column width. Does not perform column validity check. } + function InternalGetColWidths(Index: Integer): Integer; virtual; + { Returns the effective column spacing. Does not perform column validity check. } + function InternalGetEffectiveColSpacing(ACol: Integer): Integer; virtual; + { Returns the effective row spacing. Does not perform row validity check. } + function InternalGetEffectiveRowSpacing(ARow: Integer): Integer; virtual; + { Returns width and spacing for several cells according to given parameters. } + procedure InternalGetHExtent(AIndex, AColSpan: Integer; + out DestExtent, DestSpacing: Integer); virtual; + { Returns the maximum column width. Does not perform column validity check. } + function InternalGetMaxColWidth(Index: Integer): Integer; virtual; + { Returns the maximum row height. Does not perform row validity check. } + function InternalGetMaxRowHeight(Index: Integer): Integer; virtual; + { Returns the minimum column width. Does not perform column validity check. } + function InternalGetMinColWidth(Index: Integer): Integer; virtual; + { Returns the minimum row height. Does not perform row validity check. } + function InternalGetMinRowHeight(Index: Integer): Integer; virtual; + { Returns the row height. Does not perform row validity check. } + function InternalGetRowHeights(Index: Integer): Integer; virtual; + { Returns always True. } + function InternalGetSelAvail: Boolean; override; + { Returns height and spacing for several cells according to given parameters. } + procedure InternalGetVExtent(AIndex, ARowSpan: Integer; + out DestExtent, DestSpacing: Integer); virtual; + { Used internally by e.g. @link(TKCustomGrid.InsertSortedRow) to insert + a new row/column into previously sorted rows/column in a fast manner, + using a binary tree search. } + function InternalInsertNR(ByIndex, Left, Right: Integer; + SortedUp: Boolean; Compare: TKGridCompareProc): Integer; virtual; + { Used internally by @link(TKCustomGrid.KeyDown) or other methods. + Modifies ACol and ARow according to Command. } + function InternalMove(var ACol, ARow: Integer; Command: TKGridMoveCommand; + Wrap, Expanding: Boolean): Boolean; virtual; + { Used internally by @link(TKCustomGrid.UpdateSortMode) to place a modified + cell into a correct location in a sorted row or column. This is performed + in a fast manner using a binary tree search. } + function InternalInsertIfCellModifiedNR(ByIndex, Index, Left, + Right: Integer; SortedUp: Boolean; Compare: TKGridCompareProc): Integer; + { Paints a cell identified by ACol and ARow. The cell will be painted to + ACanvas according to the draw state specified by AState into a position + specified by ARect. If ADoubleBufferedCells is True, ACanvas must be + a memory device context. PaintCell ensures the correct memory bitmap for + cell double buffering will be selected to this device context. } + procedure InternalPaintCell(ACol, ARow: Integer; AState: TKGridDrawState; + const ARect, ABlockRect: TRect; ACanvas: TCanvas; Clip, Printing: Boolean); virtual; + { Used internally by e.g. @link(TKCustomGrid.SortRows) to sort rows or columns + using a non recursive quick sort algorithm. } + procedure InternalQuickSortNR(ByIndex, Left, Right: Integer; + SortedDown: Boolean; Compare: TKGridCompareProc; Exchange: TKGridExchangeProc); virtual; + { Used internally to assign new cell value. } + procedure InternalSetCell(ACol, ARow: Integer; Value: TKGridCell); virtual; + { Used internally to assign new text to a cell. } + procedure InternalSetCells(ACol, ARow: Integer; const Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); virtual; + { Sets the cell span paramters according to given parameters. Automatically + splits any existing overlapping areas. Returns a grid rectangle that can + be used to update all affected cells. } + function InternalSetCellSpan(ACol, ARow: Integer; + const Value: TKGridCellSpan): TKGridRect; virtual; + { Used internally to set column count. } + procedure InternalSetColCount(Value: Integer); virtual; + { Used internally to set fixed column count. } + procedure InternalSetFixedCols(Value: Integer); virtual; + { Used internally to set fixed row count. } + procedure InternalSetFixedRows(Value: Integer); virtual; + { Used internally to set row count. } + procedure InternalSetRowCount(Value: Integer); virtual; + { Allows the descendant to decide whether the goVirtualGrid option can be modified. } + function InternalUpdateVirtualGrid: Boolean; virtual; + { Allows the changes to be reflected. } + procedure InternalUnlockUpdate; override; + { Determines if control can be painted with OS themes. } + function IsThemed: Boolean; override; + { Overriden method - see Delphi help. Responds to keyboard events. Implements + TCustomGrid specific behavior when the user presses a key. } + procedure KeyDown(var Key: Word; Shift: TShiftState); override; + { Overriden method - performs late update. } + procedure LateUpdate(var Msg: TLMessage); override; + { Overriden method - see Delphi help. Updates grid colors. } + procedure Loaded; override; + { Calls @link(TKCustomGrid.OnMeasureCell) event handler or cell class aware equivalent. + See the @link(TKGridMeasureCellEvent) type for parameter interpretation. } + function MeasureCell(ACol, ARow: Integer; const ARect: TRect; + AState: TKGridDrawState; Priority: TKGridMeasureCellPriority): TPoint; virtual; + { Measures the grid and updates information about printed shape. } + procedure MeasurePages(var Info: TKPrintMeasureInfo); override; + { Calls @link(TKCustomGrid.OnMouseCellHint) event handler. + See the @link(TKGridCellEvent) type for parameter interpretation. } + procedure MouseCellHint(ACol, ARow: Integer; AShow: Boolean); virtual; + { Calls @link(TKCustomGrid.OnMouseClickCell) event handler. + See the @link(TKGridCellEvent) type for parameter interpretation. } + procedure MouseClickCell(ACol, ARow: Integer); virtual; + { Calls @link(TKCustomGrid.OnMouseDblClickCell) event handler. + See the @link(TKGridCellEvent) type for parameter interpretation. } + procedure MouseDblClickCell(ACol, ARow: Integer); virtual; + { Overriden method - see Delphi help. Responds to mouse events. Implements + TCustomGrid specific behavior when the user presses a mouse button. } + procedure MouseDown(Button: TMouseButton; Shift: TShiftState; + X, Y: Integer); override; + { Calls @link(TKCustomGrid.OnMouseEnterCell) event handler. + See the @link(TKGridCellEvent) type for parameter interpretation. } + procedure MouseEnterCell(ACol, ARow: Integer); virtual; + { Overriden method. Responds to WM_MOUSELEAVE message. } + procedure MouseFormLeave; override; + { Calls @link(TKCustomGrid.OnMouseLeaveCell) event handler. + See the @link(TKGridCellEvent) type for parameter interpretation. } + procedure MouseLeaveCell(ACol, ARow: Integer); virtual; + { Overriden method - see Delphi help. Responds to mouse events. Implements + TCustomGrid specific behavior when the user moves the mouse cursor. } + procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; + { Implements default behavior to visually indicate that the mouse cursor + enters or leaves the cell if goMouseOverCells is included in @link(TKCustomGrid.Options). } + procedure MouseOverCells; virtual; + { Overriden method - see Delphi help. Responds to mouse events. Implements + TCustomGrid specific behavior when the user releases a mouse button. } + procedure MouseUp(Button: TMouseButton; Shift: TShiftState; + X, Y: Integer); override; + { Returns the amount of rows in current page, minimum is 1. } + function PageHeight: Integer; virtual; + { Returns the amount of columns in current page, minimum is 1. } + function PageWidth: Integer; virtual; + { Paints a range of cells. } + function PaintCells(ACanvas: TCanvas; CellBitmap: TBitmap; + MainClipRgn: HRGN; FirstCol, LastCol, FirstRow, LastRow, X, Y, MaxX, + MaxY: Integer; Printing, PaintSelection: Boolean; const ABlockRect: TRect): TPoint; + { Paints the suggestion for drop target when dragging a column or row. } + procedure PaintDragSuggestion(ACanvas: TCanvas); virtual; + { Paints a header terminating rectangle to align the header with the right + client area edge. } + procedure PaintHeaderAlignment(ACanvas: TCanvas; ARect: TRect); virtual; + { Paints a page to a printer/preview canvas. } + procedure PaintPage; override; + { Paints the suggestion for new width/height of a column/row being resized. } + procedure PaintSizingSuggestion(ACanvas: TCanvas); virtual; + { Determines which cell lies at client coordinates specified by Point. + Set OutSide to True to evaluate a cell that does not actually lie at Point + but is the closest. Such a cell always lies at the boundary of scrollable + cell area. This is used for scrolling by mouse. InvisibleCells specifies + if some invisible cells should be considered in some cases. Currently, this + is used for scrolling by mouse, either. This function returns True if the + corresponding cell has been found. In this case, ACol and ARow contain + column and row indexes of the returned cell. } + function PointToCell(Point: TPoint; OutSide: Boolean; InvisibleCells: TKGridInvisibleCells; + out HitCol, HitRow, SelCol, SelRow: Integer): Boolean; virtual; + { Determines the possible column or row sizing state along with default sizing + parameters for client coordinates specified by Point. The possible sizing + state is returned in State and sizing parameters in Index and Pos. This + function returns True if Point is in an area where sizing of a column or + row can begin. } + function PointToSizing(Point: TPoint; var State: TKGridState; + var Index, Pos: Integer): Boolean; virtual; + { Updates drag object's (layered) window used to visually indicate the dragged + column or row. This window is updated according to mouse cursor coordinates + in MousePt, column or row index specified by Index. The Hide parameter forces + the window to hide and thus visually indicate that column or row dragging has ended. } + procedure ProcessDragWindow(const PtIni, PtCur: TPoint; Index: Integer; ColDrag, Hide: Boolean); virtual; + { Resets the @link(TKCustomGrid.LeftCol) and @link(TKCustomGrid.TopRow) property + after the @link(TKCustomGrid.FixedCols) or @link(TKCustomGrid.FixedRows) + properties have changed. } + procedure ResetTopLeft; virtual; + { Calls @link(TKCustomGrid.OnRowMoved) event handler. + See the @link(TKGridMovedEvent) type for parameter interpretation. } + procedure RowMoved(FromIndex, ToIndex: Integer); virtual; + { Calls @link(TKCustomGrid.OnRowHeightsChanged) event handler. } + procedure RowHeightsChanged(ARow: Integer); virtual; + { Tries to set input focus to the grid if @link(TKCustomGrid.EditorMode) + is False or to the inplace editor if EditorMode is True. } + procedure SafeSetFocus; virtual; + { Scrolls the scrollable cells either horizontally by DeltaHorz or vertically + by DeltaVert or in both directions. CodeHorz and CodeVert are the codes + coming from WM_HSCROLL or WM_VSCROLL messages. Set CallUpdateEditor to True + to call @link(TKCustomGrid.UpdateEditor) within this method to scroll + the inplace editor, either. Set CallUpdateEditor to False if you don't want + to scroll the inplace editor and update it by some other means, such as + @link(TKCustomgrid.SelectionMove). This method avoids inplace editor flickering + when scrolling with EditorMode = True. } + procedure Scroll(CodeHorz, CodeVert, DeltaHorz, DeltaVert: Integer; + CallUpdateEditor: Boolean); virtual; + { This method is called periodically from the timer used to automatically + scroll the scrollable cells while the mouse pointer is captured and + held outside the grid client area. } + procedure ScrollTimerHandler(Sender: TObject); virtual; + { Calls @link(TKCustomGrid.OnSelectCell) event handler or cell class aware equivalent + See the @link(TKGridSelectCellEvent) type for parameter interpretation. } + function SelectCell(ACol, ARow: Integer): Boolean; virtual; + procedure SelectionChanged(NewSelection: TKGridRect; + Flags: TKGridSelectionFlags); + { Calls @link(TKCustomGrid.OnSelectionExpand) event handler or cell class aware equivalent + See the @link(TKGridSelectionExpandEvent) type for parameter interpretation. } + function SelectionExpand(ACol, ARow: Integer): Boolean; virtual; + { Adjusts the grid rectangle identified by Sel and makes it valid. This method + is intended to adjust FSelection or a rectangle assumed to be assigned + to FSelection later. } + procedure SelectionFix(var Sel: TKGridRect); virtual; + { Initializes or expands the current selection and performs all necessary adjustments. + ACol and ARow are the indexes used to initialize or expand the selection. + Stage determines, if the selection should be initialized or expanded. + Flags forces various adjustments to be performed after the selection has been + initialized or expanded. Returns True if the selection could be changed or + would not be modified, either. } + function SelectionMove(ACol, ARow: Integer; Stage: TKGridSelectionStage; + Flags: TKGridSelectionFlags): Boolean; virtual; + { Assigns new selection and performs all necessary adjustments. } + function SelectionSet(const NewSelection: TKGridRect): Boolean; + {$IFDEF FPC} + { Overriden LCL method. This allows a custom mouse cursor to be assigned for the grid. } + procedure SetCursor(Value: TCursor); override; + {$ENDIF} + { Updates mouse cursor according to the grid state determined from current mouse + position. Returns True if cursor has been changed. } + function SetMouseCursor(X, Y: Integer): Boolean; override; + { Calls @link(TKCustomGrid.OnSizeChanged) event handler. + See the @link(TKGridSizeChangedEvent) type for parameter interpretation. } + procedure SizeChanged(Change: TKGridSizeChange; Index, Count: Integer); virtual; + { Forces the column/row dragging suggestion to be created, destroyed or + temporarilly hidden and shown, depending on the State parameter. } + procedure SuggestDrag(State: TKGridCaptureState); virtual; + { Forces the column/row sizing suggestion to be created, destroyed or + temporarilly hidden and shown, depending on the State parameter. } + procedure SuggestSizing(State: TKGridCaptureState); virtual; + { Calls @link(TKCustomGrid.OnTopLeftChanged) event handler. } + procedure TopLeftChanged; virtual; + { Updates the column axis if Horz is True and/or row axis if Vert is True. + Adjusts column widths/row heights if goAlignLastCol/goAlignLastRow + is included in @link(TKCustomGrid.Options). Adjusts scrolling range - + calls @link(TKCustomgrid.UpdateScrollRange). Invalidates columns/rows + as needed or starting by column/row index given by FirstCol/FirstRow. + Specify @link(cAll) as FirstCol/FirstRow to invalidate all columns/rows. + Performs additional actions as specified by Flags. } + procedure UpdateAxes(Horz: Boolean; FirstCol: Integer; Vert: Boolean; + FirstRow: Integer; Flags: TKGridAxisUpdateFlags); virtual; + { Updates/re-calculates the column/row span paramteres of all cells + if necessary. Fixes all broken or incomplete merged cell areas, e.g. upon + column or row moving or grid resizing. } + procedure UpdateCellSpan; virtual; + { Updates the grid size. } + procedure UpdateSize; override; + { Updates the Delphi form designer if @link(TKCustomGrid.ColWidths) or + @link(TKCustomGrid.RowHeights) have been changed. } + procedure UpdateDesigner; virtual; + { Updates the inplace editor state. Set Show to True to create and display + the inplace editor. Set Show to False to hide and destroy the inplace editor. } + procedure UpdateEditor(Show: Boolean); virtual; + { Updates the scrolling range of the column axis if Horz is True and/or row + axis if Vert is True. Set UpdateNeeded to True to force the invalidation + of respective grid areas. Set UpdateNeeded to False to let UpdateScrollRange + decide whether these need to be invalidated. } + procedure UpdateScrollRange(Horz, Vert, UpdateNeeded: Boolean); virtual; + {$IFNDEF FPC} + { Inherited method. Used to ensure correct painting for transparent inplace + editors. } + procedure WndProc(var Msg: TMessage); override; + {$ENDIF} + public + { Creates the instance. Assigns default values to properties, allocates + default column, row and cell data. } + constructor Create(AOwner: TComponent); override; + { Destroys the instance along with all allocated column, row and cell data. } + destructor Destroy; override; + { Resizes the column automatically so that the cell contents fit horizontally. + Does include merged cell areas with their base cells located in this column. + Set FixedCells to True to include fixed cells into autosizing. } + procedure AutoSizeCol(ACol: Integer; FixedCells: Boolean = True); + { Resizes the entire grid automatically so that the cell contents fit both + horizontally and vertically. Set FixedCells to True to include fixed cells + into autosizing. } + procedure AutoSizeGrid(Priority: TKGridMeasureCellPriority; FixedCells: Boolean = True); + { Resizes the row automatically so that the cell contents fit vertically. + Does include merged cell areas with their base cells located in this row. + Set FixedCells to True to include fixed cells into autosizing. } + procedure AutoSizeRow(ARow: Integer; FixedCells: Boolean = True); + { Determines if a cell specified by ACol and ARow is selected. } + function CellSelected(ACol, ARow: Integer): Boolean; virtual; + { Returns the bounding rectangle of a cell specified by ACol and ARow without the + column and row spacing areas defined by @link(TKCustomGrid.GridLineWidth). + The function returns False if the cell indexes are invalid. } + function CellRect(ACol, ARow: Integer; out R: TRect; VisibleOnly: Boolean = False): Boolean; + { Returns the left and top coordinates of a cell specified by ACol and ARow. + The function returns False if the cell indexes are invalid. } + function CellToPoint(ACol, ARow: Integer; var Point: TPoint; + VisibleOnly: Boolean = False): Boolean; virtual; + { Determines if a cell specified by ACol and ARow is visible. } + function CellVisible(ACol, ARow: Integer): Boolean; virtual; + { Clears all cells in a column identified by ACol. } + procedure ClearCol(ACol: Integer); virtual; + { Clears all cells. } + procedure ClearGrid; virtual; + { Clears all cells in a row identified by ARow. } + procedure ClearRow(ARow: Integer); virtual; + { Clears sorting mode of both rows and columns if grid sorting mode is not locked + by @link(TKCustomGrid.LockSortMode). } + procedure ClearSortMode; + { Clears sorting mode of rows if grid sorting mode is not locked + by @link(TKCustomGrid.LockSortMode). Ensures that every column has it's + @link(TKGridAxisItem.SortMode) equal to smNone. } + procedure ClearSortModeHorz; virtual; + { Clears sorting mode of columns if grid sorting mode is not locked + by @link(TKCustomGrid.LockSortMode). Ensures that every row has it's + @link(TKGridAxisItem.SortMode) equal to smNone. } + procedure ClearSortModeVert; virtual; + { Determines if a column specified by ACol can be selected, + i.e. lies in non-fixed area. } + function ColSelectable(ACol: Integer): Boolean; virtual; + { Determines if current selection includes a column specified by ACol. } + function ColSelected(ACol: Integer): Boolean; virtual; + { Determines if a column specified by ACol is valid column. } + function ColValid(ACol: Integer): Boolean; virtual; + { Decides whether a key stroke should be handled by inplace editor identified by + AEditor or by the grid. AEditor must be a descendant of + TCustomComboBox. See @link(TKGridEditorKeyPreviewEvent) for interpretation of + another parameters. } + procedure DefaultComboKeyPreview(AEditor: TComboBox; ACol, ARow: Integer; + var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); virtual; + { This function allows you to correctly set the caret position within + inplace editor identified by AEditor. AEditor must be a descendant of TCustomComboBox. + See @link(TKGridEditorSelectEvent) for interpretation of another parameters. } + procedure DefaultComboSelect(AEditor: TComboBox; SelectAll, CaretToLeft: Boolean); virtual; + { Provides default behavior while comparing two cells identified by + ACell1 and ACell2. Under current implementation, only text strings will be + compared if if any of the cells inherits @link(TKGridTextCell). } + function DefaultCompareCells(ACell1, ACell2: TKGridCell): Integer; virtual; + { Decides whether a key stroke should be handled by inplace editor identified by + AEditor or by the grid. AEditor must be a descendant of + TCustomEdit. See @link(TKGridEditorKeyPreviewEvent) for interpretation of + another parameters. } + procedure DefaultEditKeyPreview(AEditor: TCustomEdit; ACol, ARow: Integer; + var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); virtual; + { Provides default behavior for the @link(OnEditorCreate) event. } + procedure DefaultEditorCreate(ACol, ARow: Integer; + var AEditor: TWinControl); virtual; + { Provides default behavior for the @link(OnEditorDataFromGrid) event. } + procedure DefaultEditorDataFromGrid(AEditor: TWinControl; ACol, ARow: Integer; + var AssignText: Boolean); virtual; + { Provides default behavior for the @link(OnEditorDataToGrid) event. } + procedure DefaultEditorDataToGrid(AEditor: TWinControl; ACol, ARow: Integer; + var AssignText: Boolean); virtual; + { Provides default behavior for the @link(OnEditorCreate) event. } + procedure DefaultEditorDestroy(AEditor: TWinControl; ACol, ARow: Integer); virtual; + { Decides whether a key stroke should be handled by inplace editor identified by + AEditor or by the grid. Calls all implemented DefaultxxKeyPreview methods + or nothing if no ancestor is found for given AEditor. + See @link(TKGridEditorKeyPreviewEvent) for interpretation of another parameters. } + procedure DefaultEditorKeyPreview(AEditor: TWinControl; ACol, ARow: Integer; + var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); virtual; + { Provides default behavior for the @link(OnEditorResize) event. } + procedure DefaultEditorResize(AEditor: TWinControl; ACol, ARow: Integer; + var ARect: TRect); virtual; + { This function allows you to correctly set the caret position within + inplace editor identified by AEditor. Calls all implemented DefaultxxSelect methods + or nothing if no ancestor is found for given AEditor. + See @link(TKGridEditorSelectEvent) for interpretation of another parameters. } + procedure DefaultEditorSelect(AEditor: TWinControl; ACol, ARow: Integer; + SelectAll, CaretToLeft, SelectedByMouse: Boolean); virtual; + { This function allows you to correctly set the caret position within + inplace editor identified by AEditor. AEditor must be a descendant of TCustomEdit. + See @link(TKGridEditorSelectEvent) for interpretation of another parameters. } + procedure DefaultEditSelect(AEditor: TCustomEdit; SelectAll, CaretToLeft: Boolean); virtual; + { Provides default cell hint behavior. } + procedure DefaultMouseCellHint(ACol, ARow: Integer; AShow: Boolean); virtual; + { Decides whether a key stroke should be handled by inplace editor identified by + AEditor or by the grid. AEditor must be a descendant of + TScrollBar. See @link(TKGridEditorKeyPreviewEvent) for interpretation of + another parameters. } + procedure DefaultScrollBarKeyPreview(AEditor: TScrollBar; ACol, ARow: Integer; + var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); + { Deletes a column specified by At. At must be valid column index and + @link(TKCustomGrid.ColCount) must be > 1. Otherwise, nothing happens. } + procedure DeleteCol(At: Integer); virtual; + { Deletes Count columns starting at index At. At must be valid column index + and @link(TKCustomGrid.ColCount) must be > 1. Otherwise, nothing happens. + Count will be adapted so that no more but available columns will be deleted. } + procedure DeleteCols(At, Count: Integer); virtual; + { Deletes a row specified by At. At must be valid row index and + @link(TKCustomGrid.RowCount) must be > 1. Otherwise, nothing happens. } + procedure DeleteRow(At: Integer); virtual; + { Deletes Count rows starting at index At. At must be valid row index + and @link(TKCustomGrid.RowCount) must be > 1. Otherwise, nothing happens. + Count will be adapted so that no more but available rows will be deleted. } + procedure DeleteRows(At, Count: Integer); virtual; + { Retrieves the base cell if the cell given by ACol and ARow belongs to a merged cell + or returns ACol and ARow if it is a non-merged cell. } + procedure FindBaseCell(ACol, ARow: Integer; out BaseCol, BaseRow: Integer); virtual; + { Selects a cell specified by ACol and ARow. If the grid has input focus, + this cell becomes it automatically. } + procedure FocusCell(ACol, ARow: Integer); + { Returns miscellaneous information about both grid axes, i.e. column axis and row axis. } + function GetAxisInfoBoth(Mask: TKGridAxisInfoMask): TKGridAxisInfoBoth; + { Returns miscellaneous information about column axis. } + function GetAxisInfoHorz(Mask: TKGridAxisInfoMask): TKGridAxisInfo; virtual; + { Returns miscellaneous information about row axis. } + function GetAxisInfoVert(Mask: TKGridAxisInfoMask): TKGridAxisInfo; virtual; + { Returns default draw state for a cell identified by ACol and ARow. + Called by Paint - override to implement specific behavior. } + function GetDrawState(ACol, ARow: Integer; AFocused: Boolean): TKGridDrawState; virtual; + { Determines if the entire grid rectangle lies within the non-fixed and thus + selectable area. } + function GridRectSelectable(const GridRect: TKGridRect): Boolean; virtual; + { Converts a grid rectangle into client coordinates. Set VisibleOnly to True + to take only the visible part of the rectangle. Indexes in GridRect will be + automatically trimmed either to non-fixed area or to a fixed area depending + on top-left cell specified in GridRect. Set Merged to True to expand the grid + rectangle by possible merged cell areas. The returned coordinates include + column and row spacing areas defined by @link(TKCustomGrid.GridLineWidth). } + function GridRectToRect(GridRect: TKGridRect; var R: TRect; + VisibleOnly: Boolean = False; Merged: Boolean = True): Boolean; virtual; + { Determines if all indexes in GridRect are valid column or row indexes. } + function GridRectValid(const GridRect: TKGridRect): Boolean; virtual; + { Forces the cell hint to hide. } + procedure HideCellHint; + { Determines the initial index of a column identified by ACol. This function + is a part of index mapping mechanism. Initial index is assigned to a column + immediately after it is inserted into the grid either by changing + @link(TKCustomGrid.ColCount) or @link(TKCustomGrid.InsertCols). } + function InitialCol(ACol: Integer): Integer; virtual; + { Determines the current column index from initial column position given by ACol. + This function is a part of index mapping mechanism. } + function InitialColInv(ACol: Integer): Integer; virtual; + { Determines the initial index of a row identified by ARow. This function + is a part of index mapping mechanism. Initial index is assigned to a row + immediately after it is inserted into the grid either by changing + @link(TKCustomGrid.RowCount) or @link(TKCustomGrid.InsertRows). } + function InitialRow(ARow: Integer): Integer; virtual; + { Determines the current row index from initial row position given by ARow. + This function is a part of index mapping mechanism. } + function InitialRowInv(ARow: Integer): Integer; virtual; + { Inserts a new column into the grid. The new column will be inserted before + the column identified by At. You can set this parameter greater or equal + @link(TKCustomGrid.ColCount) to insert a new column behind the last column. } + procedure InsertCol(At: Integer); virtual; + { Inserts multiple new columns into the grid. The new columns will be inserted + before the column identified by At. You can set this parameter greater or equal + @link(TKCustomGrid.ColCount) to insert these after the last column. } + procedure InsertCols(At, Count: Integer); virtual; + { Inserts a new row into the grid. The new row will be inserted before + the row identified by At. You can set this parameter greater or equal + @link(TKCustomGrid.RowCount) to insert a new row behind the last row. } + procedure InsertRow(At: Integer); virtual; + { Inserts multiple new rows into the grid. The new rows will be inserted + before the row identified by At. You can set this parameter greater or equal + @link(TKCustomGrid.RowCount) to insert these after the last row. } + procedure InsertRows(At, Count: Integer); virtual; + { Inserts an empty column at the corresponding position. If columns are not sorted + at this point, InsertSortedCol does nothing and returns False. During + InsertSortedCol, a non recursive binary tree search is performed and + the @link(TKCustomGrid.OnCompareCells) event handler is called several times + with slightly different parameters than e.g. during @link(TKCustomGrid.SortCols), + i.e. the ACol1 is always @link(cInvalidIndex). You can detect it to perform + custom comparisons with the new value. } + function InsertSortedCol(out ByRow, ACol: Integer): Boolean; virtual; + { Inserts an empty row at the corresponding position. If rows are not sorted + at this point, InsertSortedRow does nothing and returns False. During + InsertSortedRow, a non recursive binary tree search is performed and + the @link(TKCustomGrid.OnCompareCells) event handler is called several times + with slightly different parameters than e.g. during @link(TKCustomGrid.SortRows), + i.e. the ARow1 is always @link(cInvalidIndex). You can detect it to perform + custom comparisons with the new value. } + function InsertSortedRow(out ByCol, ARow: Integer): Boolean; virtual; + { Invalidates the cell specified by ACol and ARow if grid updating is not locked + by @link(TKCustomControl.LockUpdate). } + procedure InvalidateCell(ACol, ARow: Integer); + { Invalidates the entire column specified by ACol if grid updating is not locked + by @link(TKCustomControl.LockUpdate). } + procedure InvalidateCol(ACol: Integer); virtual; + { Invalidates all columns starting with FirstCol if grid updating is not locked + by @link(TKCustomControl.LockUpdate). } + procedure InvalidateCols(FirstCol: Integer); virtual; + { Invalidates the current selection including the fixed cells in + @link(goIndicateSelection) mode if grid updating is not locked + by @link(TKCustomControl.LockUpdate). } + procedure InvalidateCurrentSelection; virtual; + { Invalidates the grid rectangle specified by GridRect if grid updating is not locked + by @link(TKCustomControl.LockUpdate). } + procedure InvalidateGridRect(const GR: TKGridRect; Merged: Boolean = True); virtual; + { Invalidates the entire row specified by ARow if grid updating is not locked + by @link(TKCustomControl.LockUpdate). } + procedure InvalidateRow(ARow: Integer); virtual; + { Invalidates all rows starting with FirstRow if grid updating is not locked + by @link(TKCustomControl.LockUpdate). } + procedure InvalidateRows(FirstRow: Integer); virtual; + { Invalidates any custom grid rectangle that should be treated as grid selection, + including the fixed cells in @link(goIndicateSelection) mode, + if grid updating is not locked by @link(TKCustomControl.LockUpdate). } + procedure InvalidateSelection(ASelection: TKGridRect); virtual; + { Returns True either if the DoubleBuffered property is True + or if @link(goDoubleBufferedCells) is included in grid's @link(TKCustomGrid.Options).} + function IsDoubleBuffered: Boolean; virtual; + { Locks sort mode updating so that all changes made to the cell data + will not affect the current sort status of any column or row. Every LockSortMode + call must have a corresponding @link(TKCustomGrid.UnlockSortMode) call, please use a + try-finally section. } + procedure LockSortMode; virtual; + { Determines the cell that contains client area coordinates X and Y. + If there is such a cell, the function returns True and corresponding cell + indexes are returned in ACol and ARow. Otherwise, the function returns False. } + function MouseToCell(X, Y: Integer; var ACol, ARow: Integer): Boolean; + { Moves a column from a position specified by FromIndex to a new + position specified by ToIndex. Both column indexes must be valid and + FromIndex must not equal to ToIndex. Otherwise, nothing happens. } + procedure MoveCol(FromIndex, ToIndex: Integer); virtual; + { Moves a row from a position specified by FromIndex to a new + position specified by ToIndex. Both row indexes must be valid and + FromIndex must not equal to ToIndex. Otherwise, nothing happens. } + procedure MoveRow(FromIndex, ToIndex: Integer); virtual; + { Forces to move the input focus to the next cell according to + @link(TKCustomGrid.MoveDirection) and calls OnClick event if that succeeds. } + procedure MoveToNextCell; virtual; + { Paints a cell identified by ACol and ARow to ACanvas. + This is faster way than InvalidateCell but won't work under Qt. + Set ACanvas to nil to paint to grid's Canvas. Otherwise, set AX and AY + to specify painting origin on custom ACanvas. } + procedure PaintCell(ACanvas: TCanvas; ACol, ARow: Integer; + AX: Integer = 0; AY: Integer = 0; APrinting: Boolean = False; + ABlockRect: PRect = nil); virtual; + { Paints the control to the specified canvas. } + procedure PaintToCanvas(ACanvas: TCanvas); override; + { Forces the cell class specified by @link(TKCustomGrid.CellClass) to replace + all other cell classes that do not inherit from it. Call this method to + ensure that all the cells in the grid contain instances of CellClass or those + inherited from CellClass. All possible cell class properties are copied by + the @link(TKGridCell.Assign) method. } + procedure RealizeCellClass; + { Forces the column class specified by @link(TKCustomGrid.ColClass) to replace + all other column classes that do not inherit from it. Call this method to + ensure that the entire horizontal grid axis contains instances of ColClass + or those inherited from ColClass. All possible column class properties are + copied by the @link(TKGridAxisItem.Assign) method. } + procedure RealizeColClass; + { Forces the row class specified by @link(TKCustomGrid.RowClass) to replace + all other row classes that do not inherit from it. Call this method to + ensure that the entire vertical grid axis contains instances of RowClass + or those inherited from RowClass. All possible row class properties are + copied by the @link(TKGridAxisItem.Assign) method. } + procedure RealizeRowClass; + { Determines if a row specified by ARow can be selected, + i.e. lies in non-fixed area. } + function RowSelectable(ARow: Integer): Boolean; virtual; + { Determines if current selection includes a row specified by ARow. } + function RowSelected(ARow: Integer): Boolean; virtual; + { Determines if a row specified by ARow is valid row. } + function RowValid(ARow: Integer): Boolean; virtual; + { Scrolls the non-fixed cells horizontally by AColCount cells or vertically + by ARowCount cells. If the cells cannot be scrolled, nothing happens. } + procedure ScrollBy(AColCount, ARowCount: Integer); + { Retrieves the amount of pixels corresponding to the amount of cells + specified by ADelta, relative from @link(TKCustomGrid.LeftCol) and + @link(TKCustomGrid.TopRow). } + function ScrollDeltaFromDelta(const Info: TKGridAxisInfo; ADelta: Integer): Integer; virtual; + { Determines if a cell specified by ACol and ARow should be scrolled, i.e. is + not fully visible. } + function ScrollNeeded(ACol, ARow: Integer; out DeltaHorz, DeltaVert: Integer): Boolean; virtual; + { Selects all cells. } + procedure SelectAll; + { Selects a column. } + procedure SelectCol(ACol: Integer); + { Select more columns. } + procedure SelectCols(FirstCol, Count: Integer); + { Normalize current selection. } + procedure SelectionNormalize; + { Selects a row. } + procedure SelectRow(ARow: Integer); + { Selects more rows. } + procedure SelectRows(FirstRow, Count: Integer); + { Forces the cell hint to show on screen. } + procedure ShowCellHint; + { Sorts columns by values of a row if grid sorting mode is not locked + by @link(TKCustomGrid.LockSortMode). } + procedure SortCols(ByRow: Integer; SortMode: TKGridSortMode); virtual; + { Returns True if sort mode updating is not locked, i.e. there is no open + LockSortMode and UnlockSortMode pair. } + function SortModeUnlocked: Boolean; virtual; + { Sorts rows by values of a column if grid sorting mode is not locked + by @link(TKCustomGrid.LockSortMode). } + procedure SortRows(ByCol: Integer; SortMode: TKGridSortMode); virtual; + { Unlocks sort mode updating so that all changes made to the cell data + will clear the current sort status of any column or row. } + procedure UnlockSortMode; virtual; + { Unselects range of cells. } + procedure UnselectRange; + { Updates column and row sorting mode (if there is one) if data has been + modified in a single cell. Must be called explicitly each time a cell data + has been modified if sorting interface is used. } + procedure UpdateSortMode(ACol, ARow: Integer); virtual; + { Provides fast read only access to the cell array @link(TKCustomGrid.FCells). + Any cell can be directly accessed through ArrayOfCells[RowIndex, ColIndex]. + In contrast with the @link(TKCustomGrid.Cell) property, row index + comes BEFORE column index here. It has been designed to speed up operations + with rows because most grids usually contain much more rows than colums. } + property ArrayOfCells: TKGridCells read FCells; + { Provides fast read only access to column array @link(TKCustomGrid.FCols). } + property ArrayOfCols: TKGridAxisItems read FCols; + { Provides fast read only access to row array @link(TKCustomGrid.FRows). } + property ArrayOfRows: TKGridAxisItems read FRows; + {$IFDEF FPC} + { Specifies the same as Ctl3D in Delphi. } + property Flat: Boolean read FFlat write SetFlat default False; + {$ENDIF} + { Determines if all cells are selected. } + property AllCellsSelected: Boolean read GetAllCellsSelected; + { Determines if all columns are selected. } + property AllRowsSelected: Boolean read GetAllRowsSelected; + { Determines if all columns are selected. } + property AllColsSelected: Boolean read GetAllColsSelected; + { Inherited property - see Delphi help. } + property Canvas; + { Gains access to the cell instances. New cell instances are always created + on demand by utilizing @link(TKCustomGrid.CellClass). To replace all other + cell instances with CellClass, call @link(TKCustomGrid.RealizeCellClass). } + property Cell[ACol, ARow: Integer]: TKGridCell read GetCell write SetCell; + { Cell class used to create new cell instances. Cell instances are always + created on demand. } + property CellClass: TKGridCellClass read FCellClass write FCellClass; + { Gains access to the active cell painter. } + property CellPainter: TKGridCellPainter read FCellPainter; + { Specifies the cell painter class used to create new @link(TKCustomGrid.CellPainter). + The new cell painter instance will be created immediately. } + property CellPainterClass: TKGridCellPainterClass read FCellPainterClass write SetCellPainterClass; + { Gains simplified access to the probably most used property of an textual + cell instance. If the cell instance at the position specified by ACol and ARow + does not inherit from a textual cell class @link(TKGridTextCell), it will be + created for this cell regardless of the current CellClass assignment. } + property Cells[ACol, ARow: Integer]: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF} read GetCells write SetCells; + { Specifies the column span and row span for given cell. Always specify positive + values. Reading this property may return zero or negative values, which + are used internally to find base cell of the respective merged area. } + property CellSpan[ACol, ARow: Integer]: TKGridCellSpan read GetCellSpan write SetCellSpan; + { Gains access to selection base cell. Setting Col discards the current selection + and moves focus to a new base cell in the current row that is in the new column. + The first column has an index of 0, the second column an index of 1, and so on. + If the index denotes a column that is not selectable, nothing happens. } + property Col: Integer read FSelection.Col1 write SetCol; + { Column class used to create new column instances. Column instances are always + created when @link(TKCustomGrid.ColCount) grows. } + property ColClass: TKGridColClass read FColClass write FColClass; + { Specifies the number of columns in the grid. Set ColCount to add or delete + columns at the righthand side of the grid. The value of ColCount includes + any fixed columns at the left of the grid as well as the scrollable columns + in the body of the grid. } + property ColCount: Integer read FColCount write SetColCount default cColCountDef; + { Inherited property - see Delphi help. Specifies the default background color + for client area erasing and for parts of client area not occupied by cells. } + property Color default clWindow; + { Specifies all colors used by TKCustomGrid's default painting. } + property Colors: TKGridColors read FColors write SetColors; + { Gains access to the column instances. Column instances are always + created by utilizing @link(TKCustomGrid.ColClass) when @link(TKCustomGrid.ColCount) + grows. To replace all other column instances with ColClass, call + @link(TKCustomGrid.RealizeColClass). } + property Cols[Index: Integer]: TKGridCol read GetCols; + { Indicates the width (in pixels) of all the columns in the grid. Set ColWidths + at runtime to change the width of an individual column. If the width of + a column has not been set explicitly by resizing with the mouse, or by using + the ColWidths property, its width is @link(TKCustomGrid.DefaultColWidth). } + property ColWidths[Index: Integer]: Integer read GetColWidths write SetColWidths; + { Determines the width (in pixels) of all columns that have not been explicitly + resized. Set DefaultColWidth to change the size of all columns in the grid. + When DefaultColWidth is set, columns that have been resized using the mouse + or by setting the @link(TKCustomGrid.ColWidths) property are given the DefaultColWidth + as well. When new columns are added to the grid, they are created with + a width of DefaultColWidth. } + property DefaultColWidth: Integer read FDefaultColWidth write SetDefaultColWidth default cDefaultColWidthDef; + { Dummy property - introduced for backward compatibility with TCustomGrid. } + property DefaultDrawing: Boolean read GetDefaultDrawing write SetDefaultDrawing default False; + { Determines the height (in pixels) of all rows that have not been explicitly + resized. Set DefaultRowHeight to change the size of all rows in the grid. + When DefaultRowHeight is set, rows that have been resized using the mouse + or by setting the @link(TKCustomGrid.RowHeights) property are given the DefaultRowHeight + as well. When new rows are added to the grid, they are created with + a height of DefaultRowHeight. } + property DefaultRowHeight: Integer read FDefaultRowHeight write SetDefaultRowHeight default cDefaultRowHeightDef; + { Specifies the style how the control is drawn while not enabled. } + property DisabledDrawStyle: TKGridDisabledDrawStyle read FDisabledDrawStyle write SetDisabledDrawStyle default cDisabledDrawStyleDef; + { Specifies how a column or row appears while being moved by mouse. } + property DragStyle: TKGridDragStyle read FDragStyle write SetDragStyle default cDragStyleDef; + { Returns reference to current inplace editor instance. } + property Editor: TWinControl read FEditor; + { Determines if inplace editor is active. Set EditorMode to true, at runtime, + to put the grid in edit mode. When EditorMode is true, the user can edit cells + in the grid. When the user presses F2, EditorMode is set to true. When the + user presses Enter, the value of EditorMode is toggled or, depending on + @link(goEnterMoves) and @link(TKCustomGrid.MoveDirection) configuration, + another cell is focused. Inplace editor can be activated only if goEditing + is included in @link(TKCustomGrid.Options). } + property EditorMode: Boolean read GetEditorMode write SetEditorMode; + { Determines if current inplace editor should be treated as a transparent + control from the grid's point of view. If a transparent inplace editor + needs to be painted, the cell background is painted + first to the inplace editor's Canvas/device context. Typically, check boxes + or radio buttons should appear as transparent controls in TKCustomGrid. + Unfortunatelly we must use a custom decision mechanism as there is no standard + VCL/LCL-based mechanism to design a control fully transparent in all cases. + The algorithm used to paint the cell background should work for a wide range + of controls either with or without OS themes. } + property EditorTransparency: TKGridEditorTransparency read FEditorTransparency write SetEditorTransparency default cEditorTransparencyDef; + { Returns the effective spacing between columns. This is nonzero, + if goFixedVertLine or goVertLine is included in @link(TKCustomGrid.Options). } + property EffectiveColSpacing[Index: Integer]: Integer read GetEffectiveColSpacing; + { Returns the effective spacing between rows. This is nonzero, + if goFixedHorzLine or goHorzLine is included in @link(TKCustomGrid.Options). } + property EffectiveRowSpacing[Index: Integer]: Integer read GetEffectiveRowSpacing; + { Determines if an entire column is selected. } + property EntireColSelected[Index: Integer]: Boolean read GetEntireColSelected; + { Determines number of entirely selected columns. } + property EntireSelectedColCount: Integer read GetEntireSelectedColCount; + { Determines if an entire row is selected. } + property EntireRowSelected[Index: Integer]: Boolean read GetEntireRowSelected; + { Determines number of entirely selected rows. } + property EntireSelectedRowCount: Integer read GetEntireSelectedRowCount; + { Specifies the number of columns on the left of the grid that cannot be scrolled. + Set FixedCols to create or get rid of nonscrolling columns. Nonscrolling + columns appear at the left of the grid, and are always visible, even when + the user scrolls the other columns in the grid. Use nonscrolling columns + for displaying row titles or row numbers, or to implement a scroll lock that + the user can set. } + property FixedCols: Integer read FFixedCols write SetFixedCols default cFixedColsDef; + { Specifies the number of rows on the top of the grid that cannot be scrolled. + Set FixedRows to create or get rid of nonscrolling rows. Nonscrolling rows + appear at the top of the grid, and are always visible, even when the user + scrolls the other rows in the grid. Use nonscrolling rows for displaying + column titles or column numbers. } + property FixedRows: Integer read FFixedRows write SetFixedRows default cFixedRowsDef; + { Specifies the height of the grid in pixels. If GridHeight is less than + the value of ClientHeight, all of the rows of the grid appear in the control + with an empty region below the grid. If the underlying grid is too tall + to appear in the control, GridHeight is the same as ClientHeight, + and the user must scroll to see the entire contents of the grid. } + property GridHeight: Integer read GetGridHeight; + { Specifies the width (in pixels) of the lines that separate the cells of the grid. } + property GridLineWidth: Integer read FGridLineWidth write SetGridLineWidth default cGridLineWidthDef; + { Specifies the width of the grid in pixels. If GridWidth is less than the value + of ClientWidth, all of the columns of the grid appear in the control with + an empty region to the right of the grid. If the underlying grid is + too wide to appear in the control, GridWidth is the same as ClientWidth, + and the user must scroll to see the entire contents of the grid. } + property GridWidth: Integer read GetGridWidth; + { Determines if the grid, inplace editor or any child window of inplace editor + has input focus. } + function HasFocus: Boolean; virtual; + { Returns the last (even partially) visible column in the grid. } + property LastVisibleCol: Integer read GetLastVisibleCol; + { Returns the last (even partially) visible row in the grid. } + property LastVisibleRow: Integer read GetLastVisibleRow; + { Specifies the index of the first visible scrollable column in the grid. + Set LeftCol to scroll the columns in the grid so that the column with index + LeftCol is the first column after the fixed columns. } + property LeftCol: Integer read FTopLeft.Col write SetLeftCol; + { Specifies the number of columns the grid would have if no columns would + have been deleted. } + property MaxCol: Integer read FMaxCol; + { Specifies the number of rows the grid would have if no rows would + have been deleted. } + property MaxRow: Integer read FMaxRow; + { Specifies the minimum width a column can have. } + property MinColWidth: Integer read FMinColWidth write SetMinColWidth default cMinColWidthDef; + { Specifies the minimum height a row can have. } + property MinRowHeight: Integer read FMinRowHeight write SetMinRowHeight default cMinRowHeightDef; + { Determines if more cells are selected (more than one cell). } + property MoreCellsSelected: Boolean read GetMoreCellsSelected; + { Specifies how fast the mouse cell hint should be. } + property MouseCellHintTime: Cardinal read FMouseCellHintTime write SetMouseCellHintTime default cMouseCellHintTimeDef; + { Specifies the behavior after the user presses Enter. This property has + no effect unless goEnterMoves is included in @link(TKCustomGrid.Options). } + property MoveDirection: TKGridMoveDirection read FMoveDirection write FMoveDirection default cMoveDirectionDef; + { Lists the objects for each cell in the grid. Setting Objects forces a descendant + of @link(TKGridObjectCell) to be created for the related cell. If @link(TKCustomGrid.CellClass) + contains such a descendant, then it will be used instead of TKGridObjectCell. + TObject instance given to Objects will be then stored in @link(TKGridObjectCell.CellObject) + property. In contrast to TStringGrid, the passed TObject is owned by the + TKGridObjectCell instance. Override TKGridObjectCell to implement another + behavior. } + property Objects[ACol, ARow: Integer]: TObject read GetObjects write SetObjects; + { Specifies basic display and behavioral properties of the grid. } + property Options: TKGridOptions read FOptions write SetOptions default cOptionsDef; + { Specifies extended display and behavioral properties of the grid. } + property OptionsEx: TKGridOptionsEx read FOptionsEx write SetOptionsEx default cOptionsExDef; + { Inherited property - see Delphi help. } + property ParentColor default False; + { Specifies the style how multiple cells are selected. } + property RangeSelectStyle: TKGridRangeSelectStyle read FRangeSelectStyle write FRangeSelectStyle default cRangeSelectStyleDef; + { Gains access to selection base cell. Setting Row discards the current selection + and moves focus to a new base cell in the current column that is in the new row. + The first row has an index of 0, the second row an index of 1, and so on. + If the index denotes a row that is not selectable, nothing happens. } + property Row: Integer read FSelection.Row1 write SetRow; + { Row class used to create new row instances. Row instances are always + created when @link(TKCustomGrid.RowCount) grows. } + property RowClass: TKGridRowClass read FRowClass write FRowClass; + { Specifies the number of rows in the grid. Set RowCount to add or delete rows + at the bottom of the grid. The value of RowCount includes any fixed rows at + the top of the grid as well as the scrollable rows in the body of the grid. } + property RowCount: Integer read FRowCount write SetRowCount default cRowCountDef; + { Indicates the height (in pixels) of all the rows in the grid. Set RowHeights + at runtime to change the height of an individual row. If the height of + a row has not been set explicitly by resizing with the mouse, or by using + the RowHeights property, its height is @link(TKCustomGrid.DefaultRowHeight). } + property RowHeights[Index: Integer]: Integer read GetRowHeights write SetRowHeights; + { Gains access to the row instances. Row instances are always + created by utilizing @link(TKCustomGrid.RowClass) when @link(TKCustomGrid.RowCount) + grows. To replace all other row instances with ColClass, call + @link(TKCustomGrid.RealizeRowClass). } + property Rows[Index: Integer]: TKGridRow read GetRows; + { Specifies whether the grid includes horizontal and vertical scroll bars. + If all the cells in the grid fit in the ClientWidth, no horizontal scroll bar + appears, even if ScrollBars is ssHorizontal or ssBoth. If all the cells fit + in the ClientHeight, no vertical scroll bar appears, even if ScrollBars is + ssVertical or ssBoth. } + property ScrollBars: TScrollStyle read FScrollBars write SetScrollBars default cScrollBarsDef; + { Specifies how horizontal scrollbar's trackbar scrolls the grid. } + property ScrollModeHorz: TKGridScrollMode read FScrollModeHorz write SetScrollModeHorz default cScrollModeDef; + { Specifies how vertical scrollbar's trackbar scrolls the grid. } + property ScrollModeVert: TKGridScrollMode read FScrollModeVert write SetScrollModeVert default cScrollModeDef; + { Specifies how fast the scrolling by timer should be. } + property ScrollSpeed: Cardinal read FScrollSpeed write SetScrollSpeed default cScrollSpeedDef; + { Indicates the boundaries of the current selection. Set Selection to select + a range of cells in the grid. In the TKGridRect structure, the Cell1 parameter + always denotes base selection cell and Cell2 expanded selection cell. + A base cell is always the cell that has input focus and can be currently + edited. An expanded cell denotes the other selection corner. } + property Selection: TKGridRect read GetSelection write SetSelection; + { Returns the current number of selections. Returns always a value greater or equal to 1. } + property SelectionCount: Integer read GetSelectionCount; + { Returns the selection rectangle. } + property SelectionRect: TRect read GetSelectionRect; + { Gains access to all currently existing selections. This property cannot be used + to add new selection. Please use @link(TKCustomGrid.SelectionAdd) instead. } + property Selections[Index: Integer]: TKGridRect read GetSelections write SetSelections; + { Specifies how a column or row appears while being resized by mouse. } + property SizingStyle: TKGridSizingStyle read FSizingStyle write SetSizingStyle default cSizingStyleDef; + { Returns index of the column having its SortMode property smDown or smUp. + There must be always one such column in the grid. } + property SortCol: Integer read GetSortCol; + { Returns index of the row having its SortMode property smDown or smUp. + There must be always one such row in the grid. } + property SortRow: Integer read GetSortRow; + { Specifies how sorting is performed when user clicks on clickable fixed cells + that normally indicate sorting by an arrow. } + property SortStyle: TKGridSortStyle read FSortStyle write FSortStyle default cSortStyleDef; + { Indicates whether the user can tab to specified columns in the grid if + goTabs is included in @link(TKCustomGrid.Options). Set TabStops to False + to remove the column identified by Index from the tab order. The first column + in the grid is identified by an Index of 0. Setting TabStops for fixed + columns has no effect. } + property TabStops[Index: Integer]: Boolean read GetTabStops write SetTabStops; + { Determines if cells can be painted with OS themes at the moment. Returns + True if OS themes are available and both goThemes and goThemedCells are + included in @link(TKCustomGrid.Options). } + property ThemedCells: Boolean read GetThemedCells; + { Determines if OS themes are available to the grid. } + property Themes: Boolean read GetThemes; + { If the SelectedByMouse parameter in @link(TKCustomGrid.OnEditorSelect) is True + you can set ThroughClick to True to click the inplace editor within the same + mouse click that selected this cell. } + property ThroughClick: Boolean read FThroughClick write FThroughClick; + { Specifies the index of the first visible scrollable row in the grid. + Set TopRow to scroll the rows in the grid so that the row with index + TopRow is the first row after the fixed rows. } + property TopRow: Integer read FTopLeft.Row write SetTopRow; + { Use VisibleColCount to determine the number of scrollable columns fully visible in the grid. + VisibleColCount does not include the fixed columns counted by the FixedCols property. + It does not include any partially visible columns on the right edge of the grid. } + property VisibleColCount: Integer read GetVisibleColCount; + { Indicates the area of scrollable cells visible in the grid. VisibleGridRect does not + include any fixed cells or partially visible cells on the right or bottom side of the grid. } + property VisibleGridRect: TKGridRect read GetVisibleGridRect; + { Use VisibleRowCount to determine the number of scrollable rows fully visible in the grid. + VisibleRowCount does not include the fixed rows counted by the FixedRows property. + It does not include any partially visible rows on the bottom of the grid. } + property VisibleRowCount: Integer read GetVisibleRowCount; + { OnBeginColDrag is called when the user clicks on a column to start dragging. + It enables the grid to control whether the column can be repositioned and + if so, which column. Origin is the index of the column to be dragged. + When OnBeginColDrag occurs, this is the index of the column in which the mouse + was clicked. You can change this value for application specific behavior. } + property OnBeginColDrag: TKGridBeginDragEvent read FOnBeginColDrag write FOnBeginColDrag; + { OnBeginColSizing is called when the user clicks between two columns to start + resizing. It enables the grid to control whether the column can be resized and + if so, which column. Index is the index of the column to be resized. Pos is + the X-coordinate of the sizing line. These values correspond with the default + processing initiated by mouse click. You can change both of these values + for application specific behavior. } + property OnBeginColSizing: TKGridBeginSizingEvent read FOnBeginColSizing write FOnBeginColSizing; + { OnBeginRowDrag is called when the user clicks on a row to start dragging. + It enables the grid to control whether the row can be repositioned and + if so, which row. Origin is the index of the row to be dragged. + When OnBeginRowDrag occurs, this is the index of the row in which the mouse + was clicked. You can change this value for application specific behavior. } + property OnBeginRowDrag: TKGridBeginDragEvent read FOnBeginRowDrag write FOnBeginRowDrag; + { OnBeginRowSizing is called when the user clicks between two rows to start + resizing. It enables the grid to control whether the row can be resized and + if so, which row. Index is the index of the row to be resized. Pos is + the Y-coordinate of the sizing line. These values correspond with the default + processing initiated by mouse click. You can change both of these values + for application specific behavior. } + property OnBeginRowSizing: TKGridBeginSizingEvent read FOnBeginRowSizing write FOnBeginRowSizing; + { OnCellSpan is called whenever the grid needs to get information about column + or row span of current cell. Use this only in virtual grid mode and do not write + complex code here as this event is called really VERY frequently. You must provide + the same cell span information as the TKGridCell.@link(TKGridCell.Span) for + non-virtual mode. } + property OnCellSpan: TKGridCellSpanEvent read FOnCellSpan write FOnCellSpan; + { OnChanged is called after @link(TKCustomGrid.OnEditorDataToGrid) only if + @link(TKCustomGrid.OnCompareCellInstances) returns different cells. Its purpose + is to notify the application about any changes the user made via inplace editors. + Does not work in virtual mode (if goVirtualGrid is included in @link(TKCustomGrid.Options)). } + property OnChanged: TKGridCellEvent read FOnChanged write FOnChanged; + { OnCheckColDrag validates whether the column currently selected for dragging + can be dropped at the current location. Origin is the index of the column being + actually dragged. Destination represents the potential drop target. You can + modify Destination or set CanDrop to False for application specific behavior. } + property OnCheckColDrag: TKGridCheckDragEvent read FOnCheckColDrag write FOnCheckColDrag; + { OnCheckRowDrag validates whether the row currently selected for dragging + can be dropped at the current location. Origin is the index of the row being + actually dragged. Destination represents the potential drop target. You can + modify Destination or set CanDrop to False for application specific behavior. } + property OnCheckRowDrag: TKGridCheckDragEvent read FOnCheckRowDrag write FOnCheckRowDrag; + { OnColumnMoved is called after a column has been physically moved. } + property OnColumnMoved: TKGridMovedEvent read FOnColMoved write FOnColMoved; + { OnColWidthsChanged is called whenever the width of a single or more columns changes. } + property OnColWidthsChanged: TNotifyEvent read FOnColWidthsChanged write FOnColWidthsChanged; + { OnColWidthsChangedEx is called whenever the width of a single or more columns changes. + AIndex corresponds to the first column whose width has been modified. } + property OnColWidthsChangedEx: TKGridExtentEvent read FOnColWidthsChangedEx write FOnColWidthsChangedEx; + { OnCompareCellInstances is currently called only if the grid needs to decide + whether to call the @link(TKCustomGrid.OnChanged) event handler. This event + is not called in virtual mode (if goVirtualGrid is included in @link(TKCustomGrid.Options)). } + property OnCompareCellInstances: TKGridCompareCellInstancesEvent read FOnCompareCellInstances write FOnCompareCellInstances; + { OnCompareCells is called whenever the grid needs to compare contents of two + cells. This occurs if the @link(TKCustomGrid.SortCols), @link(TKCustomGrid.SortRows), + @link(TKCustomGrid.InsertSortedCol) and @link(TKCustomGrid.InsertSortedRow) + methods are called, either programmatically or by mouse click on the first + fixed column or row. Do not write complex code here as this event is called + VERY frequently. To speed up sorting, use properties introduced for fast + data access, such as @link(TKCustomGrid.ArrayOfCells) or + @link(TKGridTextCell.TextPtr). } + property OnCompareCells: TKGridCompareCellsEvent read FOnCompareCells write FOnCompareCells; + { OnCustomSortCols is called whenever the grid needs to sort columns. Use this + event to override the default sorting algorithm. } + property OnCustomSortCols: TKGridCustomSortEvent read FOnCustomSortCols write FOnCustomSortCols; + { OnCustomSortRows is called whenever the grid needs to sort rows. Use this + event to override the default sorting algorithm. } + property OnCustomSortRows: TKGridCustomSortEvent read FOnCustomSortRows write FOnCustomSortRows; + { OnDrawCell is called whenever a cell in the grid needs to be drawn. Draw + on the cell using the methods of the Canvas property. If the OnDrawCell event + handler is not assigned, all cells in grid will be painted with the cell + class aware @link(TKGridCell.DrawCell) method. If the cell has no assigned + cell instance, it appears empty. } + property OnDrawCell: TKGridDrawCellEvent read FOnDrawCell write FOnDrawCell; + { OnEditorCreate is called whenever a cell is about to be edited. This event + handler allows you to create a custom inplace editor for each cell. The editor + should only be created, such as by means of AEditor := TEdit.Create(nil). + Correct positioning within the grid, focusing, painting etc. is maintained + later by grid itself. No manipulation requiring the editor's Handle is allowed here. } + property OnEditorCreate: TKGridEditorCreateEvent read FOnEditorCreate write FOnEditorCreate; + { OnEditorDataFromGrid is called after @link(TKCustomGrid.OnEditorCreate). + The inplace editor is correctly positioned, has a parent control, its Handle + is allocated but is still not visible. Set data from the grid to the inplace + editor in an user defined way here. Data can be set in EditorCreate but some + assignments need that the inplace editor has a parent control. Grid is always + parent control of inplace editor. } + property OnEditorDataFromGrid: TKGridEditorDataEvent read FOnEditorDataFromGrid write FOnEditorDataFromGrid; + { OnEditorDataToGrid is called if the inplace editor is about to disappear. + The inplace editor is still visible here and has a parent control. Its Handle + is still allocated. Set data from the inplace editor to the grid in an user + defined way here. Data can be transferred in @link(TKCustomGrid.EditorDestroy) + but some assignments need that the inplace editor has a parent control. } + property OnEditorDataToGrid: TKGridEditorDataEvent read FOnEditorDataToGrid write FOnEditorDataToGrid; + { OnEditorDestroy is called after @link(TKCustomGrid.OnEditorDataToGrid), + just before the inplace editor is destroyed. It is no longer visible here + and has no parent control. Its Handle is no more valid. Perform application + specific operations just before the editor is destroyed here. You need not + destroy the AEditor instance, but if so, set AEditor to nil after destroying it + Example: FreeAndNil(AEditor). } + property OnEditorDestroy: TKGridEditorDestroyEvent read FOnEditorDestroy write FOnEditorDestroy; + { OnEditorKeyPreview is called whenever inplace editor is focused and the user + presses some key that is normally handled by the grid if no inplace editor + is visible. Sometimes this key needs to be handled by the grid instead of + the inplace editor. For example, the @link(EditKeyPreview) function decides + whether the key needs to be handled by the grid or by the inplace editor. + Write your own code that is specific for your custom inplace editors. } + property OnEditorKeyPreview: TKGridEditorKeyPreviewEvent read FOnEditorKeyPreview write FOnEditorKeyPreview; + { OnEditorResize is called whenever the grid needs to relocate the inplace + editor (this might be quite often). By default, each inplace editor is always + located so that its bounding rectangle equals to the cell rectangle. + Write your own code to change this behavior. Inplace editors cannot appear + outside the edited cell, clipping is always present. Note: Not every + TWinControl instance intended as inplace editor can be arbitrary resized. } + property OnEditorResize: TKGridEditorResizeEvent read FOnEditorResize write FOnEditorResize; + { OnEditorSelect is called immediately after @link(TKCustomGrid.OnEditorDataFromGrid). + This event handler allows you to correctly set the caret position within + your inplace editor. } + property OnEditorSelect: TKGridEditorSelectEvent read FOnEditorSelect write FOnEditorSelect; + { Determines whether a particular column can be dropped immediately after + the user releases the mouse button but before the column is actually moved. } + property OnEndColDrag: TKGridEndDragEvent read FOnEndColDrag write FOnEndColDrag; + { Determines whether a particular column can be resized immediately after + the user releases the mouse button but before the column is actually resized. + This event handler has no effect if @link(TKCustomGrid.SizingStyle) is ssUpdate. } + property OnEndColSizing: TKGridEndSizingEvent read FOnEndColSizing write FOnEndColSizing; + { Determines whether a particular row can be dropped immediately after + the user releases the mouse button but before the row is actually moved. } + property OnEndRowDrag: TKGridEndDragEvent read FOnEndRowDrag write FOnEndRowDrag; + { Determines whether a particular row can be resized immediately after + the user releases the mouse button but before the row is actually resized. + This event handler has no effect if @link(TKCustomGrid.SizingStyle) is ssUpdate. } + property OnEndRowSizing: TKGridEndSizingEvent read FOnEndRowSizing write FOnEndRowSizing; + { OnExchangeCols is called whenever the grid sorts columns or needs to + exchange two columns. Typically you assign this event handler in virtual + grid mode @link(goVirtualGrid) to physically sort your data or when + implementing a custom behavior parallel to sorting cell instances owned + by the grid. This event is called from @link(TKCustomGrid.MoveCol), either. } + property OnExchangeCols: TKGridExchangeEvent read FOnExchangeCols write FOnExchangeCols; + { OnExchangeRows is called whenever the grid sorts rows or needs to + exchange two rows. Typically you assign this event handler in virtual + grid mode @link(goVirtualGrid) to physically sort your data or when + implementing a custom behavior parallel to sorting cell instances owned + by the grid. This event is called from @link(TKCustomGrid.MoveRow), either. } + property OnExchangeRows: TKGridExchangeEvent read FOnExchangeRows write FOnExchangeRows; + { OnMeasureCell is called whenever the grid needs to get the horizontal and vertical extent + of the data displayed in a cell. If the OnMeasureCell event + handler is not assigned, all cells in the grid will be measured by default. } + property OnMeasureCell: TKGridMeasureCellEvent read FOnMeasureCell write FOnMeasureCell; + { OnMouseCellHint is called whenever a cell is clicked by left mouse button. } + property OnMouseCellHint: TKGridCellHintEvent read FOnMouseCellHint write FOnMouseCellHint; + { OnMouseClickCell is called whenever a cell is clicked by left mouse button. } + property OnMouseClickCell: TKGridCellEvent read FOnMouseClickCell write FOnMouseClickCell; + { OnMouseDblClickCell is called whenever a cell is clicked by left mouse button. } + property OnMouseDblClickCell: TKGridCellEvent read FOnMouseDblClickCell write FOnMouseDblClickCell; + { OnMouseEnterCell is called whenever mouse enters a cell. } + property OnMouseEnterCell: TKGridCellEvent read FOnMouseEnterCell write FOnMouseEnterCell; + { OnMouseLeaveCell is called whenever mouse leaves a cell. } + property OnMouseLeaveCell: TKGridCellEvent read FOnMouseLeaveCell write FOnMouseLeaveCell; + { OnRowHeightsChanged is called whenever the height of a single or more rows changes. } + property OnRowHeightsChanged: TNotifyEvent read FOnRowHeightsChanged write FOnRowHeightsChanged; + { OnRowHeightsChangedEx is called whenever the height of a single or more rows changes. + AIndex corresponds to the first row whose height has been modified. } + property OnRowHeightsChangedEx: TKGridExtentEvent read FOnRowHeightsChangedEx write FOnRowHeightsChangedEx; + { OnRowMoved is called after a row has been physically moved. } + property OnRowMoved: TKGridMovedEvent read FOnRowMoved write FOnRowMoved; + { OnSelectCell is called whenever a cell is about to be selected. A cell can + be selected either by mouse or keyboard, or programmatically e.g. by the + @link(TKCustomGrid.FocusCell) method. CanSelect is True by default to allow all + selectable cells to be selected. Change this parameter to False to disallow + cell selection. A cell that cannot be selected, cannot be edited as well. + Many times you need some cells not to become editable. In this case, + let @link(TKCustomGrid.OnEditorCreate) decide it rather than OnSelectCell. } + property OnSelectCell: TKGridSelectCellEvent read FOnSelectCell write FOnSelectCell; + { OnSelectionExpand is called if the user expands the current selection. + The selection can be expanded either by mouse or keyboard, or programmatically + e.g. by the @link(TKCustomGrid.Selection) property. CanExpand is True by default + to allow all cells to become a target of selection expansion. Change this + parameter to False to disallow selection expansion.} + property OnSelectionExpand: TKGridSelectionExpandEvent read FOnSelectionExpand write FOnSelectionExpand; + { OnSizeChanged is called whenever the @link(TKCustomGrid.ColCount) or + @link(TKCustomGrid.RowCount) properties change. } + property OnSizeChanged: TKGridSizeChangedEvent read FOnSizeChanged write FOnSizeChanged; + { OnTopLeftChanged is called whenever the @link(TKCustomGrid.LeftCol) or + @link(TKCustomGrid.TopRow) properties change. } + property OnTopLeftChanged: TNotifyEvent read FOnTopLeftChanged write FOnTopLeftChanged; + end; + + { @abstract(KGrid design-time component) This is the class you use both + on run-time and design-time. } + TKGrid = class(TKCustomGrid) + published + { Inherited property - see Delphi help. } + property Align; + { Inherited property - see Delphi help. } + property Anchors; + { See TKCustomControl.@link(TKCustomControl.BorderStyle) for details. } + property BorderStyle; + { Inherited property - see Delphi help. } + property BorderWidth; + { See TKCustomGrid.@link(TKCustomGrid.ColCount) for details. } + property ColCount; + { See TKCustomGrid.@link(TKCustomGrid.Color) for details. } + property Color; + { See TKCustomGrid.@link(TKCustomGrid.Colors) for details. } + property Colors; + { Inherited property - see Delphi help. } + property Constraints; + {$IFDEF FPC} + { See TKCustomGrid.@link(TKCustomGrid.Flat) for details. } + property Flat; + {$ELSE} + { Inherited property - see Delphi help. } + property Ctl3D; + {$ENDIF} + { See TKCustomGrid.@link(TKCustomGrid.DefaultColWidth) for details. } + property DefaultColWidth; + { See TKCustomGrid.@link(TKCustomGrid.DefaultDrawing) for details. } + property DefaultDrawing; + { See TKCustomGrid.@link(TKCustomGrid.DefaultRowHeight) for details. } + property DefaultRowHeight; + { See TKCustomGrid.@link(TKCustomGrid.DisabledDrawStyle) for details. } + property DisabledDrawStyle; + { Inherited property - see Delphi help. } + property DragCursor; + { Inherited property - see Delphi help. } + property DragKind; + { Inherited property - see Delphi help. } + property DragMode; + { See TKCustomGrid.@link(TKCustomGrid.DragStyle) for details. } + property DragStyle; + { Inherited property - see Delphi help. } + property Enabled; + { See TKCustomGrid.@link(TKCustomGrid.FixedCols) for details. } + property FixedCols; + { See TKCustomGrid.@link(TKCustomGrid.FixedRows) for details. } + property FixedRows; + { Inherited property - see Delphi help. } + property Font; + { See TKCustomGrid.@link(TKCustomGrid.GridLineWidth) for details. } + property GridLineWidth; + { See TKCustomGrid.@link(TKCustomGrid.MinColWidth) for details. } + property MinColWidth; + { See TKCustomGrid.@link(TKCustomGrid.MinRowHeight) for details. } + property MinRowHeight; + { See TKCustomGrid.@link(TKCustomGrid.MouseCellHintTime) for details. } + property MouseCellHintTime; + { See TKCustomGrid.@link(TKCustomGrid.MoveDirection) for details. } + property MoveDirection; + { See TKCustomGrid.@link(TKCustomGrid.Options) for details. } + property Options; + { See TKCustomGrid.@link(TKCustomGrid.OptionsEx) for details. } + property OptionsEx; + { Inherited property - see Delphi help. } + property ParentColor; + { Inherited property - see Delphi help. } + property ParentFont; + { Inherited property - see Delphi help. } + property ParentShowHint; + { Inherited property - see Delphi help. } + property PopupMenu; + { See TKCustomGrid.@link(TKCustomGrid.RangeSelectStyle) for details. } + property RangeSelectStyle; + { See TKCustomGrid.@link(TKCustomGrid.RowCount) for details. } + property RowCount; + { See TKCustomGrid.@link(TKCustomGrid.ScrollBars) for details. } + property ScrollBars; + { See TKCustomGrid.@link(TKCustomGrid.ScrollModeHorz) for details. } + property ScrollModeHorz; + { See TKCustomGrid.@link(TKCustomGrid.ScrollModeVert) for details. } + property ScrollModeVert; + { See TKCustomGrid.@link(TKCustomGrid.ScrollSpeed) for details. } + property ScrollSpeed; + { Inherited property - see Delphi help. } + property ShowHint; + { See TKCustomGrid.@link(TKCustomGrid.SizingStyle) for details. } + property SizingStyle; + { See TKCustomGrid.@link(TKCustomGrid.SortStyle) for details. } + property SortStyle; + { Inherited property - see Delphi help. } + property TabOrder; + { Inherited property - see Delphi help. } + property TabStop default True; + { Inherited property - see Delphi help. } + property Visible; + { See TKCustomGrid.@link(TKCustomGrid.OnBeginColDrag) for details. } + property OnBeginColDrag; + { See TKCustomGrid.@link(TKCustomGrid.OnBeginColSizing) for details. } + property OnBeginColSizing; + { See TKCustomGrid.@link(TKCustomGrid.OnBeginRowDrag) for details. } + property OnBeginRowDrag; + { See TKCustomGrid.@link(TKCustomGrid.OnBeginRowSizing) for details. } + property OnBeginRowSizing; + { See TKCustomGrid.@link(TKCustomGrid.OnCellSpan) for details. } + property OnCellSpan; + { See TKCustomGrid.@link(TKCustomGrid.OnChanged) for details. } + property OnChanged; + { See TKCustomGrid.@link(TKCustomGrid.OnCheckColDrag) for details. } + property OnCheckColDrag; + { See TKCustomGrid.@link(TKCustomGrid.OnCheckRowDrag) for details. } + property OnCheckRowDrag; + { Inherited property - see Delphi help. } + property OnClick; + { See TKCustomGrid.@link(TKCustomGrid.OnColumnMoved) for details. } + property OnColumnMoved; + { See TKCustomGrid.@link(TKCustomGrid.OnColWidthsChanged) for details. } + property OnColWidthsChanged; + { See TKCustomGrid.@link(TKCustomGrid.OnColWidthsChangedEx) for details. } + property OnColWidthsChangedEx; + { See TKCustomGrid.@link(TKCustomGrid.OnCompareCellInstances) for details. } + property OnCompareCellInstances; + { See TKCustomGrid.@link(TKCustomGrid.OnCompareCells) for details. } + property OnCompareCells; + { Inherited property - see Delphi help. } + property OnContextPopup; + { See TKCustomGrid.@link(TKCustomGrid.OnCustomSortCols) for details. } + property OnCustomSortCols; + { See TKCustomGrid.@link(TKCustomGrid.OnCustomSortRows) for details. } + property OnCustomSortRows; + { Inherited property - see Delphi help. } + property OnDblClick; + { Inherited property - see Delphi help. } + property OnDockDrop; + { Inherited property - see Delphi help. } + property OnDockOver; + { Inherited property - see Delphi help. } + property OnDragDrop; + { Inherited property - see Delphi help. } + property OnDragOver; + { See TKCustomGrid.@link(TKCustomGrid.OnDrawCell) for details. } + property OnDrawCell; + { See TKCustomGrid.@link(TKCustomGrid.OnEditorCreate) for details. } + property OnEditorCreate; + { See TKCustomGrid.@link(TKCustomGrid.OnEditorDataFromGrid) for details. } + property OnEditorDataFromGrid; + { See TKCustomGrid.@link(TKCustomGrid.OnEditorDataToGrid) for details. } + property OnEditorDataToGrid; + { See TKCustomGrid.@link(TKCustomGrid.OnEditorDestroy) for details. } + property OnEditorDestroy; + { See TKCustomGrid.@link(TKCustomGrid.OnEditorKeyPreview) for details. } + property OnEditorKeyPreview; + { See TKCustomGrid.@link(TKCustomGrid.OnEditorResize) for details. } + property OnEditorResize; + { See TKCustomGrid.@link(TKCustomGrid.OnEditorSelect) for details. } + property OnEditorSelect; + { See TKCustomGrid.@link(TKCustomGrid.OnEndColDrag) for details. } + property OnEndColDrag; + { See TKCustomGrid.@link(TKCustomGrid.OnEndColSizing) for details. } + property OnEndColSizing; + { Inherited property - see Delphi help. } + property OnEndDock; + { Inherited property - see Delphi help. } + property OnEndDrag; + { See TKCustomGrid.@link(TKCustomGrid.OnEndRowDrag) for details. } + property OnEndRowDrag; + { See TKCustomGrid.@link(TKCustomGrid.OnEndRowSizing) for details. } + property OnEndRowSizing; + { Inherited property - see Delphi help. } + property OnEnter; + { Inherited property - see Delphi help. } + property OnExit; + { See TKCustomGrid.@link(TKCustomGrid.OnExchangeCols) for details. } + property OnExchangeCols; + { See TKCustomGrid.@link(TKCustomGrid.OnExchangeRows) for details. } + property OnExchangeRows; + { Inherited property - see Delphi help. } + property OnGetSiteInfo; + { Inherited property - see Delphi help. } + property OnKeyDown; + { Inherited property - see Delphi help. } + property OnKeyPress; + { Inherited property - see Delphi help. } + property OnKeyUp; + { See TKCustomGrid.@link(TKCustomGrid.OnMeasureCell) for details. } + property OnMeasureCell; + { See TKCustomGrid.@link(TKCustomGrid.OnMouseCellHint) for details. } + property OnMouseCellHint; + { See TKCustomGrid.@link(TKCustomGrid.OnMouseClickCell) for details. } + property OnMouseClickCell; + { See TKCustomGrid.@link(TKCustomGrid.OnMouseDblClickCell) for details. } + property OnMouseDblClickCell; + { Inherited property - see Delphi help. } + property OnMouseDown; + {$IFDEF COMPILER9_UP} + { Inherited property - see Delphi help. } + property OnMouseEnter; + {$ENDIF} + { See TKCustomGrid.@link(TKCustomGrid.OnMouseEnterCell) for details. } + property OnMouseEnterCell; + {$IFDEF COMPILER9_UP} + { Inherited property - see Delphi help. } + property OnMouseLeave; + {$ENDIF} + { See TKCustomGrid.@link(TKCustomGrid.OnMouseLeaveCell) for details. } + property OnMouseLeaveCell; + { Inherited property - see Delphi help. } + property OnMouseMove; + { Inherited property - see Delphi help. } + property OnMouseUp; + { Inherited property - see Delphi help. } + property OnMouseWheel; + { Inherited property - see Delphi help. } + property OnMouseWheelDown; + { Inherited property - see Delphi help. } + property OnMouseWheelUp; + { This event is called at certain phases of the actually running print job. } + property OnPrintNotify; + { This event is called after the shape is drawn onto the printer canvas. } + property OnPrintPaint; + { Inherited property - see Delphi help. } + property OnResize; + { See TKCustomGrid.@link(TKCustomGrid.OnRowHeightsChanged) for details. } + property OnRowHeightsChanged; + { See TKCustomGrid.@link(TKCustomGrid.OnRowHeightsChangedEx) for details. } + property OnRowHeightsChangedEx; + { See TKCustomGrid.@link(TKCustomGrid.OnRowMoved) for details. } + property OnRowMoved; + { See TKCustomGrid.@link(TKCustomGrid.OnSelectCell) for details. } + property OnSelectCell; + { See TKCustomGrid.@link(TKCustomGrid.OnSelectionExpand) for details. } + property OnSelectionExpand; + { See TKCustomGrid.@link(TKCustomGrid.OnSizeChanged) for details. } + property OnSizeChanged; + { Inherited property - see Delphi help. } + property OnStartDock; + { Inherited property - see Delphi help. } + property OnStartDrag; + { See TKCustomGrid.@link(TKCustomGrid.OnTopLeftChanged) for details. } + property OnTopLeftChanged; + { Inherited property - see Delphi help. } + property OnUnDock; + end; + +{ Determines if the Cell specified by ACol and ARow lies within grid rectangle R. } +function CellInGridRect(ACol, ARow: Integer; const R: TKGridRect): Boolean; + +{ Determines if the grid rectangle contains a subset of cells belonging to the + column specified by ACol. } +function ColInGridRect(ACol: Integer; const R: TKGridRect): Boolean; + +{ Obsolete function. Call TKCustomGrid.@link(TKCustomGrid.DefaultComboKeyPreview) instead. } +procedure ComboKeyPreview(AGrid: TKCustomGrid; AEditor: TComboBox; + ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); + +{ Obsolete function. Call TKCustomGrid.@link(TKCustomGrid.DefaultComboSelect) instead. } +procedure ComboSelect(AGrid: TKCustomGrid; AEditor: TComboBox; SelectAll, + CaretToLeft: Boolean); + +{ Compares two TKGridAxisItems arrays. The function returns True if the arrays are + equal in length and all corresponding TKGridAxisItem instances within both arrays + have equal property values. } +function CompareAxisItems(AxisItems1, AxisItems2: TKGridAxisItems): Boolean; + +{ Obsolete function. Implements default painting for TKCustomGrid cells. + Call TKCustomGrid.CellPainter.@link(TKGridCellPainter.DefaultDraw) instead. } +procedure DefaultDrawCell(AGrid: TKCustomGrid; ACol, ARow: Integer; ARect: TRect; + AState: TKGridDrawState; HAlign: TKHAlign; VAlign: TKVAlign; + HPadding, VPadding: Integer; const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); + +{ Obsolete function. Call TKCustomGrid.@link(TKCustomGrid.DefaultEditorKeyPreview) instead. } +procedure DefaultKeyPreview(AGrid: TKCustomGrid; AEditor: TWinControl; + ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); + +{ Obsolete function. Call TKCustomGrid.@link(TKCustomGrid.DefaultEditorSelect) instead. } +procedure DefaultSelect(AGrid: TKCustomGrid; AEditor: TWinControl; ACol, ARow: Integer; + SelectAll, CaretToLeft, SelectedByMouse: Boolean); + +{ Obsolete function. Call TKCustomGrid.@link(TKCustomGrid.DefaultEditKeyPreview) instead. } +procedure EditKeyPreview(AGrid: TKCustomGrid; AEditor: TCustomEdit; + ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); + +{ Obsolete function. Call TKCustomGrid.@link(TKCustomGrid.DefaultEditSelect) instead. } +procedure EditSelect(AGrid: TKCustomGrid; AEditor: TCustomEdit; SelectAll, + CaretToLeft: Boolean); + +{ Makes a @link(TKGridCoord) record from ACol and ARow. } +function GridPoint(ACol, ARow: Integer): TKGridCoord; + +{ Makes a @link(TKGridRect) record from ACell. Cell will be copied both to Cell1 and + Cell2 fields of the resulting grid rectangle. } +function GridRect(ACell: TKGridCoord): TKGridRect; overload; + +{ Makes a @link(TKGridRect) record from ACell1 and ACell2. All the input parameters + will be copied to the corresponding fields of the resulting grid rectangle. } +function GridRect(ACell1, ACell2: TKGridCoord): TKGridRect; overload; + +{ Makes a @link(TKGridRect) record from ACol1, ARow1, ACol2 and ARow2. All the input + parameters will be copied to the corresponding fields of the resulting grid rectangle. } +function GridRect(ACol1, ARow1, ACol2, ARow2: Integer): TKGridRect; overload; + +{ Compares two grid rectangles. Returns True if all the corresponding fields + in GridRect1 equal those in GridRect2. } +function GridRectEqual(const GridRect1, GridRect2: TKGridRect): Boolean; + +{ Makes a @link(TKGridCellSpan) record from AColumns and ARows. } +function MakeCellSpan(AColumns, ARows: Integer): TKGridCellSpan; + +{ Makes Cell1 field of GridRect always top-left cell and Cell2 field always + bottom-right cell. } +procedure NormalizeGridRect(var GridRect: TKGridRect); + +{ Determines if the grid rectangle contains a subset of cells belonging to the + row specified by ARow. } +function RowInGridRect(ARow: Integer; const R: TKGridRect): Boolean; + +{ Obsolete function. Call TKCustomGrid.@link(TKCustomGrid.DefaultScrollBarKeyPreview) instead. } +procedure ScrollBarKeyPreview(AGrid: TKCustomGrid; AEditor: TScrollBar; + ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); + +implementation + +uses + Math, TypInfo +{$IFDEF USE_THEMES} + , Themes + {$IFNDEF FPC} + , UxTheme + {$ENDIF} +{$ENDIF} + ; + +function CellInGridRect(ACol, ARow: Integer; const R: TKGridRect): Boolean; +begin + Result := ( + (R.Col1 <= R.Col2) and (ACol >= R.Col1) and (ACol <= R.Col2) or + (R.Col1 > R.Col2) and (ACol >= R.Col2) and (ACol <= R.Col1) + ) and ( + (R.Row1 <= R.Row2) and (ARow >= R.Row1) and (ARow <= R.Row2) or + (R.Row1 > R.Row2) and (ARow >= R.Row2) and (ARow <= R.Row1) + ) +end; + +function ColInGridRect(ACol: Integer; const R: TKGridRect): Boolean; +begin + Result := ( + (R.Col1 <= R.Col2) and (ACol >= R.Col1) and (ACol <= R.Col2) or + (R.Col1 > R.Col2) and (ACol >= R.Col2) and (ACol <= R.Col1) + ); +end; + +procedure ComboKeyPreview(AGrid: TKCustomGrid; AEditor: TComboBox; + ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); +begin + AGrid.DefaultComboKeyPreview(AEditor, ACol, ARow, Key, ShiftState, IsGridKey); +end; + +procedure ComboSelect(AGrid: TKCustomGrid; AEditor: TComboBox; SelectAll, + CaretToLeft: Boolean); +begin + AGrid.DefaultComboSelect(AEditor, SelectAll, CaretToLeft); +end; + +function CompareAxisItems(AxisItems1, AxisItems2: TKGridAxisItems): Boolean; +var + I: Integer; +begin + Result := Length(AxisItems1) = Length(AxisItems2); + if Result then + for I := 0 to Length(AxisItems1) - 1 do + if not AxisItems1[I].Equals(AxisItems2[I]) then + begin + Result := False; + Exit; + end; +end; + +procedure DefaultDrawCell(AGrid: TKCustomGrid; ACol, ARow: Integer; ARect: TRect; + AState: TKGridDrawState; HAlign: TKHAlign; VAlign: TKVAlign; + HPadding, VPadding: Integer; const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); +begin + with AGrid do + begin + CellPainter.Initialize; + CellPainter.Col := ACol; + CellPainter.Row := ARow; + CellPainter.CellRect := ARect; + CellPainter.State := AState; + CellPainter.HAlign := HAlign; + CellPainter.VAlign := VAlign; + CellPainter.HPadding := HPadding; + CellPainter.VPadding := VPadding; + CellPainter.Text := AText; + CellPainter.DefaultDraw; + end; +end; + +procedure DefaultKeyPreview(AGrid: TKCustomGrid; AEditor: TWinControl; + ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); +begin + AGrid.DefaultEditorKeyPreview(AEditor, ACol, ARow, Key, ShiftState, IsGridKey); +end; + +procedure DefaultSelect(AGrid: TKCustomGrid; AEditor: TWinControl; ACol, ARow: Integer; + SelectAll, CaretToLeft, SelectedByMouse: Boolean); +begin + AGrid.DefaultEditorSelect(AEditor, ACol, ARow, SelectAll, CaretToLeft, SelectedByMouse); +end; + +function DirectionToCommand(Direction: TKGridMoveDirection): TKGridMoveCommand; +begin + case Direction of + mdDown: Result := mcDown; + mdLeft: Result := mcLeft; + mdRight: Result := mcRight; + else + Result := mcUp; + end; +end; + +procedure DoEditKeyPreview(ATextLen, ASelStart, ASelLength, ALineCount: Integer; + AMultiLine, AStartLine, AEndLine: Boolean; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); +begin + if ((Key in [VK_LEFT, VK_HOME]) and ((ASelStart > 0) or (ASelLength > 1))) or // 1 to support TMaskEdit + ((Key in [VK_RIGHT, VK_END]) and ((ASelStart < ATextLen) or (ASelLength > 0))) or + ((Key in [VK_PRIOR, VK_UP]) and AMultiLine and (not AStartLine or (ASelLength > 0) and (ASelLength < ATextLen))) or + ((Key in [VK_NEXT, VK_DOWN]) and AMultiLine and (not AEndLine or (ASelLength > 0) and (ASelLength < ATextLen))) or + (Key = VK_RETURN) and AMultiLine then + IsGridKey := False; +end; + +procedure EditKeyPreview(AGrid: TKCustomGrid; AEditor: TCustomEdit; + ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); +begin + AGrid.DefaultEditKeyPreview(AEditor, ACol, ARow, Key, ShiftState, IsGridKey); +end; + +procedure EditSelect(AGrid: TKCustomGrid; AEditor: TCustomEdit; SelectAll, + CaretToLeft: Boolean); +begin + AGrid.DefaultEditSelect(AEditor, SelectAll, CaretToLeft); +end; + +function GridRectEqual(const GridRect1, GridRect2: TKGridRect): Boolean; +begin + Result := CompareMem(@GridRect1, @GridRect2, SizeOf(TKGridRect)); +end; + +function GridPoint(ACol, ARow: Integer): TKGridCoord; +begin + with Result do + begin + Col := ACol; + Row := ARow; + end; +end; + +function GridRect(ACell: TKGridCoord): TKGridRect; overload; +begin + with Result do + begin + Col1 := ACell.Col; + Col2 := ACell.Col; + Row1 := ACell.Row; + Row2 := ACell.Row; + end; +end; + +function GridRect(ACell1, ACell2: TKGridCoord): TKGridRect; overload; +begin + with Result do + begin + Cell1 := ACell1; + Cell2 := ACell2; + end; +end; + +function GridRect(ACol1, ARow1, ACol2, ARow2: Integer): TKGridRect; overload; +begin + with Result do + begin + Col1 := ACol1; + Col2 := ACol2; + Row1 := ARow1; + Row2 := ARow2; + end; +end; + +function MakeCellSpan(AColumns, ARows: Integer): TKGridCellSpan; +begin + Result.ColSpan := AColumns; + Result.RowSpan := ARows; +end; + +procedure NormalizeGridRect(var GridRect: TKGridRect); +begin + if GridRect.Col1 > GridRect.Col2 then Exchange(GridRect.Col1, GridRect.Col2); + if GridRect.Row1 > GridRect.Row2 then Exchange(GridRect.Row1, GridRect.Row2); +end; + +function RowInGridRect(ARow: Integer; const R: TKGridRect): Boolean; +begin + Result := ( + (R.Row1 <= R.Row2) and (ARow >= R.Row1) and (ARow <= R.Row2) or + (R.Row1 > R.Row2) and (ARow >= R.Row2) and (ARow <= R.Row1) + ); +end; + +procedure ScrollBarKeyPreview(AGrid: TKCustomGrid; AEditor: TScrollBar; + ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); +begin + AGrid.DefaultScrollBarKeyPreview(AEditor, ACol, ARow, Key, ShiftState, IsGridKey); +end; + +{ TKGridAxisItem } + +constructor TKGridAxisItem.Create(AGrid: TKCustomGrid); +begin + FGrid := AGrid; + FCanResize := True; + FExtent := 0; + FInitialPos := -1; + FMaxExtent := 0; + FMinExtent := 0; + FSortArrowIndex := 0; +end; + +procedure TKGridAxisItem.Assign(Source: TKGridAxisItem); +begin + FCanResize := Source.CanResize; + FExtent := Source.Extent; +// FInitialPos := Source.InitialPos; +end; + +procedure TKGridAxisItem.BeginDrag(var Origin: Integer; + const MousePt: TPoint; var CanBeginDrag: Boolean); +begin +end; + +procedure TKGridAxisItem.CheckDrag(Origin: Integer; var Destination: Integer; + const MousePt: TPoint; var CanDrop: Boolean); +begin +end; + +procedure TKGridAxisItem.EndDrag(Origin, Destination: Integer; + const MousePt: TPoint; var CanEndDrag: Boolean); +begin +end; + +function TKGridAxisItem.{$ifdef COMPILER12_UP}EqualProperties{$ELSE}Equals{$ENDIF}(Item: TKGridAxisItem): Boolean; +begin + Result := (Item.Extent = FExtent) and + (Item.CanResize = FCanResize); +end; + +procedure TKGridAxisItem.SetMaxExtent(AValue: Integer); +begin + if FMinExtent > 0 then + AValue := Max(AValue, FMinExtent); + if (AValue >= 0) and (FMaxExtent <> AValue) then + begin + FMaxExtent := AValue; + if (FMaxExtent > 0) and (FExtent > FMaxExtent) then + Extent := FMaxExtent; + end; +end; + +procedure TKGridAxisItem.SetMinExtent(AValue: Integer); +begin + if FMaxExtent > 0 then + AValue := Min(AValue, FMaxExtent); + if (AValue >= 0) and (FMinExtent <> AValue) then + begin + FMinExtent := AValue; + if (FMinExtent > 0) and Visible and (FExtent < FMinExtent) then + Extent := FMinExtent; + end; +end; + +function TKGridAxisItem.GetVisible: Boolean; +begin + Result := FExtent > 0; +end; + +{ TKGridCol } + +constructor TKGridCol.Create(AGrid: TKCustomGrid); +begin + inherited; + FExtent := FGrid.DefaultColWidth; + FCellHint := False; + FTabStop := True; +end; + +procedure TKGridCol.Assign(Source: TKGridAxisItem); +begin + inherited; + if Source is TKGridCol then + begin + FCellHint := TKGridCol(Source).CellHint; + FTabStop := TKGridCol(Source).TabStop; + end; +end; + +procedure TKGridCol.Assign(Source: TStrings); +var + I, J: Integer; + Cell: TKGridCell; +begin + if Assigned(FGrid) and (Source.Count > 0) and FindCol(I) then + begin + FGrid.LockUpdate; + try + for J := 0 to Min(FGrid.RowCount, Source.Count) - 1 do + begin + Cell := FGrid.ArrayOfCells[J, I]; + if Cell is TKGridTextCell then + TKGridTextCell(Cell).Text := Source[J]; + end; + finally + FGrid.UnlockUpdate; + end; + end; +end; + +{$IFDEF TKGRID_USE_JCL} +procedure TKGridCol.Assign(Source: TWideStrings); +var + I, J: Integer; + Cell: TKGridCell; +begin + if Assigned(FGrid) and (Source.Count > 0) and FindCol(I) then + begin + FGrid.LockUpdate; + try + for J := 0 to Min(FGrid.RowCount, Source.Count) - 1 do + begin + Cell := FGrid.ArrayOfCells[J, I]; + if Cell is TKGridTextCell then + TKGridTextCell(Cell).Text := Source[J]; + end; + finally + FGrid.UnlockUpdate; + end; + end; +end; +{$ENDIF} + +procedure TKGridCol.Clear; +var + I: Integer; +begin + if Assigned(FGrid) and FindCol(I) then + FGrid.ClearCol(I); +end; + +function TKGridCol.{$ifdef COMPILER12_UP}EqualProperties{$ELSE}Equals{$ENDIF}(Item: TKGridAxisItem): Boolean; +begin + Result := inherited Equals(Item) and (Item is TKGridCol) and + (TKGridCol(Item).TabStop = FTabStop) and + (TKGridCol(Item).CellHint = FCellHint); +end; + +function TKGridCol.FindCol(out Index: Integer): Boolean; +begin + Result := False; + Index := 0; + while Index < FGrid.ColCount do + begin + if FGrid.ArrayOfCols[Index] <> Self then + Inc(Index) + else + begin + Result := True; + Exit; + end; + end; +end; + +function TKGridCol.GetObjects(Index: Integer): TObject; +var + I: Integer; + Cell: TKGridCell; +begin + Result := nil; + if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.RowValid(Index) and FindCol(I) then + begin + Cell := FGrid.ArrayOfCells[Index, I]; + if Cell is TKGridObjectCell then + Result := TKGridObjectCell(Cell).CellObject; + end; +end; + +function TKGridCol.GetStrings(Index: Integer): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; +var + I: Integer; + Cell: TKGridCell; +begin + Result := ''; + if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.RowValid(Index) and FindCol(I) then + begin + Cell := FGrid.ArrayOfCells[Index, I]; + if Cell is TKGridTextCell then + Result := TKGridTextCell(Cell).Text; + end; +end; + +procedure TKGridCol.SetExtent(const Value: Integer); +var + I: Integer; +begin + if (Value >= 0) and (Value <> FExtent) then + begin + if Assigned(FGrid) and FGrid.UpdateUnlocked and not FGrid.Flag(cGF_GridUpdates) and FindCol(I) then + FGrid.ColWidths[I] := Value + else + begin + if FExtent <> 0 then FBackExtent := FExtent; + FExtent := Value; + end; + end; +end; + +procedure TKGridCol.SetObjects(Index: Integer; const Value: TObject); +var + I: Integer; + Cell: TKGridCell; +begin + if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.RowValid(Index) and FindCol(I) then + begin + Cell := FGrid.ArrayOfCells[Index, I]; + if Cell is TKGridObjectCell then + TKGridObjectCell(Cell).CellObject := Value; + end; +end; + +procedure TKGridCol.SetSortArrowIndex(Value: Integer); +var + I: Integer; +begin + Value := Max(Value, 0); + if Value <> FSortArrowIndex then + begin + FSortArrowIndex := Value; + if Assigned(FGrid) and FGrid.UpdateUnlocked and not FGrid.Flag(cGF_GridUpdates) and + (FSortMode <> smNone) and (FGrid.FixedRows > 1) and FindCol(I) then + FGrid.InvalidateGridRect(GridRect(I, 0, I, FGrid.FixedRows - 1)); + end; +end; + +procedure TKGridCol.SetSortMode(const Value: TKGridSortMode); +var + I: Integer; +begin + if (Value <> FSortMode) and FGrid.SortModeUnlocked then + begin + if Assigned(FGrid) and FGrid.UpdateUnlocked and not FGrid.Flag(cGF_GridUpdates) and FindCol(I) then + FGrid.SortRows(I, Value) + else + FSortMode := Value; + end; +end; + +procedure TKGridCol.SetStrings(Index: Integer; const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); +var + I: Integer; + Cell: TKGridCell; +begin + if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.RowValid(Index) and FindCol(I) then + begin + Cell := FGrid.ArrayOfCells[Index, I]; + if Cell is TKGridTextCell then + TKGridObjectCell(Cell).Text := Value; + end; +end; + +procedure TKGridCol.SetVisible(Value: Boolean); +begin + if Value then + begin + if FBackExtent <= FGrid.MinColWidth then + Extent := FGrid.MinColWidth + else + Extent := FBackExtent; + end else + Extent := 0 +end; + +{ TKGridRow } + +constructor TKGridRow.Create(AGrid: TKCustomGrid); +begin + inherited; + FExtent := FGrid.DefaultRowHeight; +end; + +procedure TKGridRow.Assign(Source: TStrings); +var + I, J: Integer; + Cell: TKGridCell; +begin + if Assigned(FGrid) and (Source.Count > 0) and FindRow(I) then + begin + FGrid.LockUpdate; + try + for J := 0 to Min(FGrid.ColCount, Source.Count) - 1 do + begin + Cell := FGrid.ArrayOfCells[I, J]; + if Cell is TKGridTextCell then + TKGridTextCell(Cell).Text := Source[J]; + end; + finally + FGrid.UnlockUpdate; + end; + end; +end; + +{$IFDEF TKGRID_USE_JCL} +procedure TKGridRow.Assign(Source: TWideStrings); +var + I, J: Integer; + Cell: TKGridCell; +begin + if Assigned(FGrid) and (Source.Count > 0) and FindRow(I) then + begin + FGrid.LockUpdate; + try + for J := 0 to Min(FGrid.ColCount, Source.Count) - 1 do + begin + Cell := FGrid.ArrayOfCells[I, J]; + if Cell is TKGridTextCell then + TKGridTextCell(Cell).Text := Source[J]; + end; + finally + FGrid.UnlockUpdate; + end; + end; +end; +{$ENDIF} + +procedure TKGridRow.Clear; +var + I: Integer; +begin + for I := 0 to FGrid.RowCount - 1 do + if FGrid.Rows[I] = Self then + begin + FGrid.ClearRow(I); + Exit; + end; +end; + +function TKGridRow.FindRow(out Index: Integer): Boolean; +begin + Result := False; + Index := 0; + while Index < FGrid.RowCount do + begin + if FGrid.ArrayOfRows[Index] <> Self then + Inc(Index) + else + begin + Result := True; + Exit; + end; + end; +end; + +function TKGridRow.GetObjects(Index: Integer): TObject; +var + I: Integer; + Cell: TKGridCell; +begin + Result := nil; + if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.ColValid(Index) and FindRow(I) then + begin + Cell := FGrid.ArrayOfCells[I, Index]; + if Cell is TKGridObjectCell then + Result := TKGridObjectCell(Cell).CellObject; + end; +end; + +function TKGridRow.GetStrings(Index: Integer): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; +var + I: Integer; + Cell: TKGridCell; +begin + Result := ''; + if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.ColValid(Index) and FindRow(I) then + begin + Cell := FGrid.ArrayOfCells[I, Index]; + if Cell is TKGridTextCell then + Result := TKGridTextCell(Cell).Text; + end; +end; + +procedure TKGridRow.SetExtent(const Value: Integer); +var + I: Integer; +begin + if (Value >= 0) and (Value <> FExtent) then + begin + if Assigned(FGrid) and FGrid.UpdateUnlocked and not FGrid.Flag(cGF_GridUpdates) and FindRow(I) then + FGrid.RowHeights[I] := Value + else + begin + if FExtent <> 0 then FBackExtent := FExtent; + FExtent := Value; + end; + end; +end; + +procedure TKGridRow.SetObjects(Index: Integer; const Value: TObject); +var + I: Integer; + Cell: TKGridCell; +begin + if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.ColValid(Index) and FindRow(I) then + begin + Cell := FGrid.ArrayOfCells[I, Index]; + if Cell is TKGridObjectCell then + TKGridObjectCell(Cell).CellObject := Value; + end; +end; + +procedure TKGridRow.SetSortArrowIndex(Value: Integer); +var + I: Integer; +begin + Value := Max(Value, 0); + if Value <> FSortArrowIndex then + begin + FSortArrowIndex := Value; + if Assigned(FGrid) and FGrid.UpdateUnlocked and not FGrid.Flag(cGF_GridUpdates) and + (FSortMode <> smNone) and (FGrid.FixedCols > 1) and FindRow(I) then + FGrid.InvalidateGridRect(GridRect(0, I, FGrid.FixedCols - 1, I)); + end; +end; + +procedure TKGridRow.SetSortMode(const Value: TKGridSortMode); +var + I: Integer; +begin + if (Value <> FSortMode) and FGrid.SortModeUnlocked then + begin + if Assigned(FGrid) and FGrid.UpdateUnlocked and not FGrid.Flag(cGF_GridUpdates) and FindRow(I) then + FGrid.SortCols(I, Value) + else + FSortMode := Value; + end; +end; + +procedure TKGridRow.SetStrings(Index: Integer; const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); +var + I: Integer; + Cell: TKGridCell; +begin + if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.ColValid(Index) and FindRow(I) then + begin + Cell := FGrid.ArrayOfCells[I, Index]; + if Cell is TKGridTextCell then + TKGridTextCell(Cell).Text := Value; + end; +end; + + +procedure TKGridRow.SetVisible(Value: Boolean); +begin + if Value then + begin + if FBackExtent <= FGrid.MinRowHeight then + Extent := FGrid.MinRowHeight + else + Extent := FBackExtent; + end else + Extent := 0 +end; + +{ TKGridCell } + +constructor TKGridCell.Create(AGrid: TKCustomGrid); +begin + FGrid := AGrid; + Initialize; +end; + +procedure TKGridCell.Assign(Source: TKGridCell); +begin + BeforeUpdate; + FSpan := Source.Span; + AfterUpdate; +end; + +procedure TKGridCell.Clear; +begin + BeforeUpdate; + try + Initialize; + finally + AfterUpdate; + end; +end; + +procedure TKGridCell.AfterUpdate; +var + Cells: TKGridCells; + Info: TKGridAxisInfoBoth; + I, J, HExtent, VExtent: Integer; +begin + if Assigned(FGrid) and FGrid.UpdateUnlocked and not FGrid.Flag(cGF_GridUpdates) then + begin + // invalidate cell, iterate only visible cells in a fast way + Cells := FGrid.ArrayOfCells; + Info := FGrid.GetAxisInfoBoth([]); + I := 0; HExtent := 0; + while (I < Info.Horz.TotalCellCount) and (HExtent < Info.Horz.ClientExtent) do + begin + if I = Info.Horz.FixedCellCount then + I := Info.Horz.FirstGridCell; // switch to first visible nonfixed cell + J := 0; VExtent := 0; + while (J < Info.Vert.TotalCellCount) and (VExtent < Info.Vert.ClientExtent) do + begin + if J = Info.Vert.FixedCellCount then + J := Info.Vert.FirstGridCell; // switch to first visible nonfixed cell + if Cells[J, I] = Self then + begin + FGrid.InvalidateCell(I, J); + Exit; + end; + Inc(VExtent, Info.Vert.CellExtent(J) + Info.Vert.EffectiveSpacing(J)); + Inc(J); + end; + Inc(HExtent, Info.Horz.CellExtent(I) + Info.Horz.EffectiveSpacing(I)); + Inc(I); + end; + end; +end; + +procedure TKGridCell.BeforeUpdate; +begin + // empty +end; + +procedure TKGridCell.ApplyDrawProperties; +begin +end; + +procedure TKGridCell.DrawCell(ACol, ARow: Integer; const ARect: TRect; + State: TKGridDrawState); +begin + FGrid.CellPainter.DefaultDraw; +end; + +procedure TKGridCell.EditorCreate(ACol, ARow: Integer; var AEditor: TWinControl); +begin + FGrid.DefaultEditorCreate(ACol, ARow, AEditor); +end; + +procedure TKGridCell.EditorDataFromGrid(AEditor: TWinControl; ACol, ARow: Integer; + var AssignText: Boolean); +begin + FGrid.DefaultEditorDataFromGrid(AEditor, ACol, ARow, AssignText); +end; + +procedure TKGridCell.EditorDataToGrid(AEditor: TWinControl; ACol, ARow: Integer; + var AssignText: Boolean); +begin + FGrid.DefaultEditorDataToGrid(AEditor, ACol, ARow, AssignText); +end; + +procedure TKGridCell.EditorDestroy(var AEditor: TWinControl; ACol, ARow: Integer); +begin + FGrid.DefaultEditorDestroy(AEditor, ACol, ARow); +end; + +procedure TKGridCell.EditorKeyPreview(AEditor: TWinControl; ACol, ARow: Integer; + var Key: Word; Shift: TShiftState; var IsGridKey: Boolean); +begin + FGrid.DefaultEditorKeyPreview(AEditor, ACol, ARow, Key, Shift, IsGridKey); +end; + +procedure TKGridCell.EditorResize(AEditor: TWinControl; ACol, ARow: Integer; + var ARect: TRect); +begin + FGrid.DefaultEditorResize(AEditor, ACol, ARow, ARect); +end; + +procedure TKGridCell.EditorSelect(AEditor: TWinControl; ACol, ARow: Integer; + SelectAll, CaretToLeft, SelectedByMouse: Boolean); +begin + FGrid.DefaultEditorSelect(AEditor, ACol, ARow, SelectAll, CaretToLeft, SelectedByMouse); +end; + +function TKGridCell.FindCell(out ACol, ARow: Integer): Boolean; +var + I, J: Integer; +begin + Result := False; + if Assigned(FGrid) then + for I := 0 to FGrid.ColCount - 1 do + for J := 0 to FGrid.RowCount - 1 do + if FGrid.ArrayOfCells[J, I] = Self then + begin + ACol := I; + ARow := J; + Result := True; + Exit; + end; +end; + +procedure TKGridCell.Initialize; +begin + FSpan := MakeCellSpan(1, 1); +end; + +procedure TKGridCell.MeasureCell(ACol, ARow: Integer; const ARect: TRect; + State: TKGridDrawState; Priority: TKGridMeasureCellPriority; var Extent: TPoint); +begin + Extent := FGrid.CellPainter.DefaultMeasure(Priority); +end; + +procedure TKGridCell.SelectCell(ACol, ARow: Integer; var ACanSelect: Boolean); +begin +end; + +procedure TKGridCell.SelectionExpand(ACol, ARow: Integer; var ACanExpand: Boolean); +begin +end; + +procedure TKGridCell.SetColSpan(const Value: Integer); +var + ACol, ARow: Integer; +begin + if Value <> FSpan.ColSpan then + begin + if Assigned(FGrid) and not FGrid.Flag(cGF_GridUpdates) then + begin + if FindCell(ACol, ARow) then + FGrid.CellSpan[ACol, ARow] := MakeCellSpan(Value, FSpan.RowSpan); + end else + FSpan.ColSpan := Value; + end; +end; + +procedure TKGridCell.SetRowSpan(const Value: Integer); +var + ACol, ARow: Integer; +begin + if Value <> FSpan.RowSpan then + begin + if Assigned(FGrid) and not FGrid.Flag(cGF_GridUpdates) then + begin + if FindCell(ACol, ARow) then + FGrid.CellSpan[ACol, ARow] := MakeCellSpan(FSpan.ColSpan, Value); + end else + FSpan.RowSpan := Value; + end; +end; + +procedure TKGridCell.SetSpan(const Value: TKGridCellSpan); +var + ACol, ARow: Integer; +begin + if (Value.ColSpan <> FSpan.ColSpan) or (Value.RowSpan <> FSpan.RowSpan) then + begin + if Assigned(FGrid) and not FGrid.Flag(cGF_GridUpdates) then + begin + if FindCell(ACol, ARow) then + FGrid.CellSpan[ACol, ARow] := Value; + end else + FSpan := Value; + end; +end; + +{ TKGridTextCell } + +constructor TKGridTextCell.Create(AGrid: TKCustomGrid); +begin +{$IFDEF STRING_IS_UNICODE} + FText := ''; +{$ELSE} + FText := nil; +{$ENDIF} + inherited; +end; + +destructor TKGridTextCell.Destroy; +begin + inherited; +{$IFNDEF STRING_IS_UNICODE} + FreeMem(FText); +{$ENDIF} +end; + +procedure TKGridTextCell.ApplyDrawProperties; +begin + FGrid.CellPainter.Text := Text; +end; + +procedure TKGridTextCell.Assign(Source: TKGridCell); +begin + inherited; + if Source is TKGridTextCell then + SetText(TKGridTextCell(Source).TextPtr); +end; + +procedure TKGridTextCell.AssignText(const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); +{$IFNDEF STRING_IS_UNICODE} +var + Len: Integer; +{$ENDIF} +begin +{$IFDEF STRING_IS_UNICODE} + FText := Value; +{$ELSE} + Len := (Length(Value) + 1) * SizeOf(WideChar); + ReallocMem(FText, Len); + if Value <> '' then + Move(Value[1], FText^, Len) + else if FText <> nil then + FText[0] := #0; +{$ENDIF} +end; + +procedure TKGridTextCell.EditorCreate(ACol, ARow: Integer; var AEditor: TWinControl); +begin + AEditor := TEdit.Create(nil); +end; + +{$IFDEF STRING_IS_UNICODE} +function TKGridTextCell.GetTextPtr: PChar; +begin + Result := PChar(FText); +end; +{$ELSE} +function TKGridTextCell.GetText: WideString; +begin + Result := FText; +end; +{$ENDIF} + +procedure TKGridTextCell.Initialize; +begin + inherited; +{$IFDEF STRING_IS_UNICODE} + FText := ''; +{$ELSE} + FreeMem(FText); + FText := nil; +{$ENDIF} +end; + +procedure TKGridTextCell.SetText(const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); +begin +{$IFDEF STRING_IS_UNICODE} + if Value <> FText then +{$ELSE} + if CompareWideChars(PWideChar(Value), FText) <> 0 then +{$ENDIF} + begin + BeforeUpdate; + AssignText(Value); + AfterUpdate; + end; +end; + +{ TKGridAttrTextCell } + +constructor TKGridAttrTextCell.Create(AGrid: TKCustomGrid); +begin + inherited; + FBrush := TBrush.Create; + FBrush.OnChange := BrushChange; + FBrushChanged := False; + FFont := TFont.Create; + FFont.OnChange := FontChange; + FFontChanged := False; + Initialize; +end; + +destructor TKGridAttrTextCell.Destroy; +begin + FBrush.Free; + FFont.Free; + inherited; +end; + +procedure TKGridAttrTextCell.ApplyDrawProperties; +var + AColor: TColor; +begin + inherited; + if FGrid.CellPainter.State * [gdSelected] <> [] then + begin + // Brush remains unaffected by default + if FFontChanged then + begin + // Font color remains unaffected by default + AColor := FGrid.CellPainter.Canvas.Font.Color; + FGrid.CellPainter.Canvas.Font := FFont; + FGrid.CellPainter.Canvas.Font.Color := AColor; + if FGrid.CellPainter.FPrinting then + FGrid.CellPainter.Canvas.Font.Height := Abs(FFont.Height); + end; + end else + begin + FGrid.CellPainter.BackColor := FBackColor; + if FBrushChanged then + begin + FGrid.CellPainter.Canvas.Brush := FBrush; + {$IFNDEF FPC} + SetBrushOrgEx(FGrid.CellPainter.Canvas.Handle, FGrid.CellPainter.CellRect.Left, + FGrid.CellPainter.CellRect.Top, nil); + {$ENDIF} + end; + if FFontChanged then + begin + FGrid.CellPainter.Canvas.Font := FFont; + if FGrid.CellPainter.FPrinting then + FGrid.CellPainter.Canvas.Font.Height := Abs(FFont.Height); + end; + end; + FGrid.CellPainter.HAlign := FHAlign; + FGrid.CellPainter.VAlign := FVAlign; + FGrid.CellPainter.HPadding := FHPadding; + FGrid.CellPainter.VPadding := FVPadding; +end; + +procedure TKGridAttrTextCell.Assign(Source: TKGridCell); +begin + inherited; + if Source is TKGridAttrTextCell then + begin + FBackColor := TKGridAttrTextCell(Source).BackColor; + FBrush.Assign(TKGridAttrTextCell(Source).Brush); + FBrushChanged := TKGridAttrTextCell(Source).BrushChanged; + FFont.Assign(TKGridAttrTextCell(Source).Font); + FFontChanged := TKGridAttrTextCell(Source).FontChanged; + FHAlign := TKGridAttrTextCell(Source).HAlign; + FHPadding := TKGridAttrTextCell(Source).HPadding; + FVAlign := TKGridAttrTextCell(Source).VAlign; + FVPadding := TKGridAttrTextCell(Source).VPadding; + end; +end; + +procedure TKGridAttrTextCell.BrushChange(Sender: TObject); +begin + BeforeUpdate; + FBrushChanged := True; + AfterUpdate; +end; + +procedure TKGridAttrTextCell.FontChange(Sender: TObject); +begin + BeforeUpdate; + FFontChanged := True; + AfterUpdate; +end; + +procedure TKGridAttrTextCell.Initialize; +begin + inherited; + FBackColor := clWindow; + FHAlign := halLeft; + FHPadding := 2; + FVAlign := valCenter; + FVPadding := 0; + // no defaults for Brush and Font! +end; + +procedure TKGridAttrTextCell.SetBackColor(const Value: TColor); +begin + if Value <> FBackColor then + begin + BeforeUpdate; + FBackColor := Value; + AfterUpdate; + end; +end; + +procedure TKGridAttrTextCell.SetFHAlign(const Value: TKHAlign); +begin + if Value <> FHAlign then + begin + BeforeUpdate; + FHAlign := Value; + AfterUpdate; + end; +end; + +procedure TKGridAttrTextCell.SetAttributes(const AValue: TKTextAttributes); +begin + if AValue <> FAttributes then + begin + BeforeUpdate; + FAttributes := AValue; + AfterUpdate; + end; +end; + +procedure TKGridAttrTextCell.SetFHPadding(const Value: Integer); +begin + if Value <> FHPadding then + begin + BeforeUpdate; + FHPadding := Value; + AfterUpdate; + end; +end; + +procedure TKGridAttrTextCell.SetFVAlign(const Value: TKVAlign); +begin + if Value <> FVAlign then + begin + BeforeUpdate; + FVAlign := Value; + AfterUpdate; + end; +end; + +procedure TKGridAttrTextCell.SetFVPadding(const Value: Integer); +begin + if Value <> FVPadding then + begin + BeforeUpdate; + FVPadding := Value; + AfterUpdate; + end; +end; + +{ TKGridObjectCell } + +constructor TKGridObjectCell.Create(AGrid: TKCustomGrid); +begin + FCellObject := nil; + inherited; +end; + +destructor TKGridObjectCell.Destroy; +begin + inherited; + FCellObject.Free; +end; + +procedure TKGridObjectCell.Assign(Source: TKGridCell); +var + Obj: TObject; +begin + inherited; + if Source is TKGridObjectCell then + begin + Obj := TKGridObjectCell(Source).CellObject; + if (Obj is TPersistent) and (FCellObject.ClassType = Obj.ClassType) then + TPersistent(FCellObject).Assign(TPersistent(Obj)); + end; +end; + +procedure TKGridObjectCell.Initialize; +begin + inherited; + FreeAndNil(FCellObject); +end; + +procedure TKGridObjectCell.SetCellObject(Value: TObject); +begin + if Value <> FCellObject then + begin + FCellObject.Free; + FCellObject := Value; + end; +end; + +{ TKGridCellPainter } + +constructor TKGridCellPainter.Create(AGrid: TKCustomGrid); +begin + inherited Create; + FGrid := AGrid; + FCanvas := nil; + FCol := 0; + FClipLock := 0; + FRgn := 0; + FRow := 0; + FState := []; + FValidClipping := False; + FSortArrow := TKAlphaBitmap.CreateFromRes('KGRID_SORT_ARROW'); + Initialize; +end; + +destructor TKGridCellPainter.Destroy; +begin + FSortArrow.Free; + inherited; +end; + +function TKGridCellPainter.BeginClip; +var + R: TRect; +begin + if FClipLock = 0 then with FCanvas do + begin + R := FCellRect; + TranslateRectToDevice(Handle, R); + FValidClipping := ExtSelectClipRect(Handle, R, RGN_AND, FRgn); + end; + Inc(FClipLock); + Result := FValidClipping; +end; + +procedure TKGridCellPainter.BeginDraw; +begin + DefaultAttributes; +end; + +function TKGridCellPainter.CellCheckBoxRect(var BaseRect: TRect; out Bounds, Interior: TRect; StretchMode: TKStretchMode): Boolean; +begin + if FCheckBox and not IsRectEmpty(BaseRect) then + begin + ExcludeShapeFromBaseRect(BaseRect, cCheckBoxFrameSize{$IFDEF LCLQT} + 1{$ENDIF}, cCheckBoxFrameSize, FCheckBoxHAlign, + FCheckBoxVAlign, FCheckBoxHPadding, FCheckBoxVPadding, StretchMode, Bounds, Interior); + Result := True; + end else + Result := False; +end; + +function TKGridCellPainter.CellGraphicRect(var BaseRect: TRect; out Bounds, Interior: TRect; StretchMode: TKStretchMode): Boolean; +begin + if Assigned(FGraphic) and not IsRectEmpty(BaseRect) then + begin + ExcludeShapeFromBaseRect(BaseRect, FGraphic.Width, FGraphic.Height, FGraphicHAlign, + FGraphicVAlign, FGraphicHPadding, FGraphicVPadding, StretchMode, Bounds, Interior); + Result := True; + end else + Result := False; +end; + +function TKGridCellPainter.CellSortArrowRect(var BaseRect: TRect; out Bounds, Interior: TRect): Boolean; +var + ArrowWidth: Integer; +begin + ArrowWidth := SortArrowWidth; + if (ArrowWidth > 0) and not IsRectEmpty(BaseRect) then + begin + ExcludeShapeFromBaseRect(BaseRect, ArrowWidth, BaseRect.Bottom - BaseRect.Top, FSortArrowHAlign, + valCenter, FSortArrowHPadding, 0, stmNone, Bounds, Interior); + Result := True; + end else + Result := False; +end; + +function TKGridCellPainter.CellTextExtent(const BaseRect: TRect; out Extent: TPoint): Boolean; +var + R: TRect; +begin + if (FText <> '') and not IsRectEmpty(BaseRect) then + begin + R := BaseRect; + DrawAlignedText(FCanvas, R, FHAlign, FVAlign, + FHPadding, FVPadding, FText, FBackColor, FAttributes + [taCalcRect]); + Extent.X := R.Right - R.Left; + Extent.Y := R.Bottom - R.Top; + Result := True; + end else + Result := False; +end; + +function TKGridCellPainter.CellTextRect(var BaseRect: TRect; out Bounds, Interior: TRect): Boolean; +var + Extent: TPoint; +begin + if CellTextExtent(BaseRect, Extent) then + begin + ExcludeShapeFromBaseRect(BaseRect, Extent.X, Extent.Y, FHAlign, + FVAlign, FHPadding, FVPadding, stmNone, Bounds, Interior); + Result := True; + end else + Result := False; +end; + +procedure TKGridCellPainter.DefaultAttributes; +var + Color: TColor; +begin + Initialize; + // prepare default brush and font style + with FCanvas do + begin + Brush.Style := bsSolid; + Pen.Style := psSolid; + Pen.Mode := pmCopy; + Font := FGrid.Font; + if FPrinting then + Font.Height := Abs(FGrid.Font.Height); + if gdFixed in FState then + begin + // aki: + if gdSelected in FState then + Color := FGrid.Colors.SelectedFixedCellBkGnd + else if (goIndicateSelection in FGrid.Options) and (FGrid.ColSelected(FCol) and + not (goRowSelect in FGrid.Options) or FGrid.RowSelected(FRow)) then + Color := FGrid.Colors.FixedCellIndication + else + Color := FGrid.Colors.FixedCellBkGnd; + if gdMouseDown in FState then + Brush.Color := BrightColor(Color, 0.6, bsOfTop) + else + Brush.Color := Color; + Font.Color := FGrid.Colors.FixedCellText; + end else if gdSelected in FState then + begin + if FPrinting or FGrid.HasFocus then + begin + if (FGrid.Col = FCol) and (FGrid.Row = FRow) then + begin + Brush.Color := FGrid.Colors.FocusedCellBkGnd; + Font.Color := FGrid.Colors.FocusedCellText; + end else + begin + Brush.Color := FGrid.Colors.FocusedRangeBkGnd; + Font.Color := FGrid.Colors.FocusedRangeText; + end; + end else + begin + if (FGrid.Col = FCol) and (FGrid.Row = FRow) then + begin + Brush.Color := FGrid.Colors.SelectedCellBkGnd; + Font.Color := FGrid.Colors.SelectedCellText; + end else + begin + Brush.Color := FGrid.Colors.SelectedRangeBkGnd; + Font.Color := FGrid.Colors.SelectedRangeText; + end; + end; + end else + begin + Brush.Color := FGrid.Colors.CellBkGnd; + Font.Color := FGrid.Colors.CellText; + end; + end; +end; + +procedure TKGridCellPainter.DefaultDraw; +begin + if gdFixed in FState then + begin + if (FRow < FGrid.FixedRows) and (goHeader in FGrid.Options) then + DrawHeaderCellBackground(FCellRect) + else + DrawFixedCellBackground(FCellRect); + end + else if gdSelected in FState then + begin + if FGrid.Options * [goRowSelect, goRangeSelect] <> [] then + DrawSelectedCellBackground(FBlockRect, @FCellRect) + else + DrawSelectedCellBackground(FCellRect) + end else + DrawNormalCellBackground(FCellRect); + DrawCellCommon; +end; + +function TKGridCellPainter.DefaultEdges: Cardinal; +begin + Result := 0; + if goFixedHorzLine in FGrid.Options then + begin + Result := BF_TOP; + if not (goAlignLastRow in FGrid.Options) or (FRow < FGrid.RowCount - 1) then + Result := Result or BF_BOTTOM; + end; + if goFixedVertLine in FGrid.Options then + begin + Result := Result or BF_LEFT; + if not (goAlignLastCol in FGrid.Options) or (FCol < FGrid.ColCount - 1) then + Result := Result or BF_RIGHT; + end; +end; + +function TKGridCellPainter.DefaultMeasure(Priority: TKGridMeasureCellPriority): TPoint; +const + cMaxAutoSizeColWidth = 10000; + cMaxAutoSizeRowHeight = 10000; + cMaxAutoSizeStretchImageHeight = 1024; +var + BaseRect, Bounds, Interior: TRect; +begin + BaseRect := FCellRect; + case Priority of + mpColWidth: BaseRect.Right := cMaxAutoSizeColWidth; + mpRowHeight: BaseRect.Bottom := cMaxAutoSizeRowHeight; + else + BaseRect.Right := cMaxAutoSizeColWidth; + BaseRect.Bottom := cMaxAutoSizeRowHeight; + end; + if Assigned(FGraphic) and (FGraphicStretchMode in [stmZoom, stmZoomInOnly]) then + BaseRect.Bottom := Min(BaseRect.Bottom, BaseRect.Top + (FGraphicVPadding shl 1) + cMaxAutoSizeStretchImageHeight); +// BaseRect.Right := MaxInt; // keep cell height, maximize cell width and cut each object from BaseRect + Result.X := 0; + Result.Y := 0; + if CellSortArrowRect(BaseRect, Bounds, Interior) then + begin + Inc(Result.X, Bounds.Right - Bounds.Left); + Result.Y := Interior.Bottom - Interior.Top; + end; + if CellCheckBoxRect(BaseRect, Bounds, Interior, stmNone) then // for measuring always consider check box frame with original size + begin + Inc(Result.X, Bounds.Right - Bounds.Left); + Result.Y := Max(Result.Y, Interior.Bottom - Interior.Top + (FCheckBoxVPadding shl 1)); + end; + if CellGraphicRect(BaseRect, Bounds, Interior, FGraphicStretchMode) then // for measuring consider stretched image as for drawing + begin + Inc(Result.X, Bounds.Right - Bounds.Left); + Result.Y := Max(Result.Y, Interior.Bottom - Interior.Top + (FGraphicVPadding shl 1)); + end; + if CellTextExtent(BaseRect, Interior.TopLeft) then + begin + Inc(Result.X, Interior.Left + (FHPadding shl 1)); + Result.Y := Max(Result.Y, Interior.Top + (FVPadding shl 1)); + end; +end; + +procedure TKGridCellPainter.DrawCellCommon; +var + BaseRect, Bounds, Interior, BoundsSA, InteriorSA: TRect; + IsSortArrow: Boolean; +begin + if not (gdEdited in FState) then + begin + BaseRect := FCellRect; + IsSortArrow := CellSortArrowRect(BaseRect, BoundsSA, InteriorSA); + if CellCheckBoxRect(BaseRect, Bounds, Interior, stmZoomOutOnly) then // disallow zoom in for check box frame + DrawCellCheckBox(Bounds, Interior); + if CellGraphicRect(BaseRect, Bounds, Interior, FGraphicStretchMode) then + DrawCellGraphic(Bounds, Interior); + if not IsRectEmpty(BaseRect) then + begin + if FButton then + DrawCellButton(BaseRect) + else + DrawCellText(BaseRect); + end; + if IsSortArrow then + DrawCellSortArrow(BoundsSA, InteriorSA); + if gdSelected in FState then + DrawCellFocus(FCellRect); + end; +end; + +procedure TKGridCellPainter.DrawButtonFrame(const ARect: TRect); +var + BM: TBitmap; + TmpCanvas: TCanvas; + TmpRect: TRect; + ButtonState: Integer; + IsHot: Boolean; + MousePt: TPoint; +{$IFDEF USE_THEMES} + ButtonTheme: TThemedButton; +{$ENDIF} +begin + // a LOT of tweaking here... +{$IF DEFINED(USE_WINAPI) OR DEFINED(LCLQT) } // GTK2 cannot strech and paint on bitmap canvas, grrr.. + if CanvasScaled(FCanvas) {$IFDEF USE_WINAPI}and FGrid.ThemedCells{$ENDIF} then + begin + BM := TBitmap.Create; + BM.Width := ARect.Right - ARect.Left; + BM.Height := ARect.Bottom - ARect.Top; + BM.Canvas.Brush.Assign(FCanvas.Brush); + TmpRect := Rect(0, 0, BM.Width, BM.Height); + BM.Canvas.FillRect(TmpRect); + TmpCanvas := BM.Canvas; + end else +{$IFEND} + begin + BM := nil; + TmpRect := ARect; + TmpCanvas := FCanvas; + end; + try + MousePt := FGrid.ScreenToClient(Mouse.CursorPos); + IsHot := (gdMouseOver in FState) and + (not FHotFrameOnly or PtInRect(ARect, MousePt)); + {$IFDEF USE_THEMES} + if FGrid.ThemedCells then + begin + if FGrid.Enabled then + if FButtonPressed then + ButtonTheme := tbPushButtonPressed + else + if IsHot then + ButtonTheme := tbPushButtonHot + else + ButtonTheme := tbPushButtonNormal + else + ButtonTheme := tbPushButtonDisabled; + ThemeServices.DrawElement(TmpCanvas.Handle, ThemeServices.GetElementDetails(ButtonTheme), TmpRect); + end else + {$ENDIF} + begin + ButtonState := DFCS_BUTTONPUSH; + if FButtonPressed then ButtonState := ButtonState or DFCS_PUSHED; + if not FGrid.Enabled then ButtonState := ButtonState or DFCS_INACTIVE; + DrawFrameControl(TmpCanvas.Handle, TmpRect, DFC_BUTTON, ButtonState); + end; + if BM <> nil then + FCanvas.Draw(ARect.Left, ARect.Top, BM); + finally + BM.Free; + end; +end; + +procedure TKGridCellPainter.DrawCellButton(Bounds: TRect); +begin + DrawButtonFrame(Bounds); + DrawCellText(Bounds); +end; + +procedure TKGridCellPainter.DrawCellCheckBox(const Bounds, Interior: TRect); +begin + DrawCheckBoxFrame(Interior); +end; + +procedure TKGridCellPainter.DrawCellGraphic(const Bounds, Interior: TRect); +begin + if Assigned(FGraphic) then + begin + if FGraphicStretchMode = stmZoom then + SafeStretchDraw(FCanvas, Interior, FGraphic, FBackColor) + else if BeginClip then + try + SafeStretchDraw(FCanvas, Interior, FGraphic, FBackColor); + finally + EndClip; + end; + end; +end; + +procedure TKGridCellPainter.DrawCellFocus(const ARect: TRect; SkipTest: Boolean); +begin + if (gdFocused in FState) and (SkipTest or (FGrid.Options * [goRangeSelect, goRowSelect, + goDrawFocusSelected] = [goDrawFocusSelected])) then + begin + // to ensure coming DrawFocusRect will be painted correctly: + SetBkColor(FCanvas.Handle, $FFFFFF); + SetTextColor(FCanvas.Handle, 0); + FCanvas.DrawFocusRect(FCellRect); + end; +end; + +procedure TKGridCellPainter.DrawCellSortArrow(const Bounds, Interior: TRect); +var + ArrowCopy: TKAlphaBitmap; + Mirror, Rotate: Boolean; +begin + if FSortArrow <> nil then + begin + if BeginClip then + try + Mirror := FState * [gdColsSortedDown, gdRowsSortedDown] <> []; + Rotate := FState * [gdColsSortedDown, gdColsSortedUp] <> []; + ArrowCopy := TKAlphaBitmap.Create; + try + if Rotate then + begin + ArrowCopy.CopyFromRotated(FSortArrow); + if Mirror then + ArrowCopy.MirrorHorz; + end else + begin + ArrowCopy.CopyFrom(FSortArrow); + if Mirror then + ArrowCopy.MirrorVert; + end; + ArrowCopy.AlphaDrawTo(FCanvas, Interior.Left, Interior.Top + (Interior.Bottom - Interior.Top - ArrowCopy.Height) div 2); + finally + ArrowCopy.Free; + end; + finally + EndClip; + end; + end; +end; + +procedure TKGridCellPainter.DrawCellText(var ARect: TRect); +var + TextAttributes: TKTextAttributes; +begin + TextAttributes := FAttributes; +{ if FFillCellBackground then + Include(TextAttributes, taFillRect) + else + Exclude(TextAttributes, taFillRect);} + DrawAlignedText(FCanvas, ARect, FHAlign, FVAlign, + FHPadding, FVPadding, FText, FBackColor, TextAttributes); +end; + +procedure TKGridCellPainter.DrawCheckBoxFrame(const ARect: TRect); +var + BM: TBitmap; + TmpCanvas: TCanvas; + TmpRect: TRect; + State: Integer; + IsHot: Boolean; + MousePt: TPoint; +{$IFDEF USE_THEMES} + CheckBoxTheme: TThemedButton; +{$ENDIF} +begin + // a LOT of tweaking here... +{$IF DEFINED(USE_WINAPI) OR DEFINED(LCLQT) } // GTK2 cannot strech and paint on bitmap canvas, grrr.. + if CanvasScaled(FCanvas) {$IFDEF USE_WINAPI}and FGrid.ThemedCells{$ENDIF} then + begin + BM := TBitmap.Create; + BM.Width := ARect.Right - ARect.Left; + BM.Height := ARect.Bottom - ARect.Top; + BM.Canvas.Brush.Assign(FCanvas.Brush); + TmpRect := Rect(0, 0, BM.Width, BM.Height); + BM.Canvas.FillRect(TmpRect); + TmpCanvas := BM.Canvas; + end else +{$IFEND} + begin + BM := nil; + TmpRect := ARect; + TmpCanvas := FCanvas; + end; + try + {$IFDEF USE_THEMES} + MousePt := FGrid.ScreenToClient(Mouse.CursorPos); + IsHot := (gdMouseOver in FState) and + (not FHotFrameOnly or PtInRect(ARect, MousePt)); + if FGrid.ThemedCells then + begin + if FGrid.Enabled then + case FCheckBoxState of + cbChecked: + begin + if IsHot then + CheckBoxTheme := tbCheckBoxCheckedHot + else + CheckBoxTheme := tbCheckBoxCheckedNormal; + end; + cbUnchecked: + begin + if IsHot then + CheckBoxTheme := tbCheckBoxUncheckedHot + else + CheckBoxTheme := tbCheckBoxUncheckedNormal; + end; + else + if IsHot then + CheckBoxTheme := tbCheckBoxMixedHot + else + CheckBoxTheme := tbCheckBoxMixedNormal; + end + else + case FCheckboxState of + cbChecked: + CheckBoxTheme := tbCheckBoxCheckedDisabled; + cbUnchecked: + CheckBoxTheme := tbCheckBoxUncheckedDisabled; + else + CheckBoxTheme := tbCheckBoxMixedDisabled; + end; + ThemeServices.DrawElement(TmpCanvas.Handle, ThemeServices.GetElementDetails(CheckBoxTheme), TmpRect); + end else + {$ENDIF} + begin + State := DFCS_BUTTON3STATE; + case FCheckBoxState of + cbChecked: + State := State or DFCS_CHECKED; +// cbGrayed: +// State := State or DFCS_GRAYED; + end; + if not FGrid.Enabled then State := State or DFCS_INACTIVE; + DrawFrameControl(TmpCanvas.Handle, TmpRect, DFC_BUTTON, State); + end; + if BM <> nil then + FCanvas.Draw(ARect.Left, ARect.Top, BM); + finally + BM.Free; + end; +end; + +procedure TKGridCellPainter.DrawHeaderCellBackground(const ARect: TRect); +{$IFDEF USE_THEMES} +var + Details: TThemedElementDetails; + Header: TThemedHeader; + TmpRect: TRect; +{$ENDIF} +begin +{$IFDEF USE_THEMES} + if FGrid.ThemedCells then with ThemeServices do + begin + if gdSelected in FState then + Header := thHeaderItemPressed + else if gdMouseDown in FState then + Header := thHeaderItemPressed + else if gdMouseOver in FState then + Header := thHeaderItemHot + else + Header := thHeaderItemNormal; + { The background for the themed header is messy. HasTransparentParts returns + always True and we cannot call DrawParentBackground as this is wrong + approach here. So for this reason, thHeaderItemNormal is always supposed + to be visually not transparent. We paint it only if double buffering is + present because double buffer is a temporary memory and, of course, + the screen content is not copied back to the double buffer. } + TmpRect := ARect; + Inc(TmpRect.Bottom); // it is nicer + if FGrid.IsDoubleBuffered and (Header <> thHeaderItemNormal) then + DrawElement(FCanvas.Handle, GetElementDetails(thHeaderItemNormal), TmpRect); + Details := GetElementDetails(Header); + DrawElement(FCanvas.Handle, Details, TmpRect); + end else +{$ENDIF} + DrawFixedCellNonThemedBackground(ARect); +end; + +procedure TKGridCellPainter.DrawEmptyCell; +begin + DrawNormalCellBackground(FCellRect); +end; + +procedure TKGridCellPainter.DrawFixedCell; +begin + DrawFixedCellBackground(FCellRect); + DrawCellCommon; +end; + +procedure TKGridCellPainter.DrawFixedCellBackground(const ARect: TRect); +{$IFDEF USE_THEMES} +var + Color1, Color2: TColor; +{$ENDIF} +begin +{$IFDEF USE_THEMES} + if FGrid.ThemedCells and (gxFixedThemedCells in FGrid.OptionsEx) then + DrawHeaderCellBackground(ARect) + else if FGrid.ThemedCells then + begin + DrawFilledRectangle(FCanvas, ARect, FBackColor); + if {$IFDEF FPC}not FGrid.Flat{$ELSE}FGrid.Ctl3D{$ENDIF} then + begin + if gdMouseDown in FState then + begin + Color1 := FGrid.Colors.FixedThemedCellShadow; + Color2 := FGrid.Colors.FixedThemedCellHighlight; + end else + begin + Color1 := FGrid.Colors.FixedThemedCellHighlight; + Color2 := FGrid.Colors.FixedThemedCellShadow; + end; + DrawEdges(FCanvas, ARect, Color1, Color2, DefaultEdges); + end; + end else +{$ENDIF} + DrawFixedCellNonThemedBackground(ARect); +end; + +procedure TKGridCellPainter.DrawFixedCellNonThemedBackground(const ARect: TRect); +{$IFDEF USE_WINAPI} +var + R: TRect; +{$ENDIF} +begin + DrawFilledRectangle(FCanvas, ARect, FBackColor); + if {$IFDEF FPC}not FGrid.Flat{$ELSE}FGrid.Ctl3D{$ENDIF} and not (gdMouseDown in FState) then + begin + {$IFDEF USE_WINAPI} + // looks somewhat better though + R := ARect; + DrawEdge(FCanvas.Handle, R, BDR_RAISEDINNER, DefaultEdges); + {$ELSE} + DrawEdges(FCanvas, ARect, cl3DHilight, cl3DShadow, DefaultEdges); + {$ENDIF} + end; +end; + +procedure TKGridCellPainter.DrawHeaderCell; +begin + DrawHeaderCellBackground(FCellRect); + DrawCellCommon; +end; + +procedure TKGridCellPainter.DrawNormalCellBackground(const ARect: TRect); +begin + DrawFilledRectangle(FCanvas, ARect, FBackColor); +end; + +procedure TKGridCellPainter.DrawSelectableCell; +begin + if gdSelected in FState then + DrawSelectedCellBackground(FCellRect) + else + DrawNormalCellBackground(FCellRect); + DrawCellCommon; +end; + +procedure TKGridCellPainter.DrawSelectedCellBackground(const ARect: TRect; RClip: PRect); +var +{$IFDEF USE_THEMES} + {$IF (DEFINED(COMPILER9_UP) OR DEFINED(FPC)) AND DEFINED(USE_WINAPI)} + {$IFDEF FPC} + Details: TThemedElementDetails; + {$ELSE} + SelectionTheme: HTHEME; + {$ENDIF} + Color: TColorRef; + {$IFEND} +{$ENDIF} + R: TRect; +begin +{$IFDEF USE_THEMES} + {$IF (DEFINED(COMPILER9_UP) OR DEFINED(FPC)) AND DEFINED(USE_WINAPI)} + if FGrid.ThemedCells and (Win32MajorVersion >= 6) then // Windows Vista and later + begin + // make the background brigther + if FPrinting or FGrid.HasFocus then + FCanvas.Brush.Color := BrightColor(FCanvas.Brush.Color, 0.8, bsOfTop) + else + FCanvas.Brush.Color := clWhite; + if RClip <> nil then + FCanvas.FillRect(RClip^) + else + FCanvas.FillRect(ARect); + {$IFDEF FPC} + Details := ThemeServices.GetElementDetails(tmPopupItemHot); + ThemeServices.DrawElement(FCanvas.Handle, Details, ARect, RClip); + Color := clWindowText; // getting text color not supported + {$ELSE} + SelectionTheme := ThemeServices.Theme[teMenu]; + DrawThemeBackground(SelectionTheme, FCanvas.Handle, MENU_POPUPITEM, MPI_HOT, ARect, RClip); + GetThemeColor(SelectionTheme, MENU_POPUPITEM, MPI_HOT, TMT_TEXTCOLOR, Color); + {$ENDIF} + FCanvas.Font.Color := Color; + end else + {$IFEND} +{$ENDIF} + begin + if RClip <> nil then + R := RClip^ + else + R := ARect; + DrawFilledRectangle(FCanvas, R, FBackColor); + end; +end; + +procedure TKGridCellPainter.DrawThemedFixedCell; +begin + DrawFixedCellBackground(FCellRect); + DrawCellCommon; +end; + +procedure TKGridCellPainter.DrawThemedHeaderCell; +begin + DrawHeaderCellBackground(FCellRect); + DrawCellCommon; +end; + +procedure TKGridCellPainter.EndClip; +begin + if FClipLock > 0 then with FCanvas do + begin + Dec(FClipLock); + if FClipLock = 0 then + begin + FinalizePrevRgn(Handle, FRgn); + FValidClipping := False; + end; + end; +end; + +procedure TKGridCellPainter.EndDraw; +begin +end; + +function TKGridCellPainter.GetCheckBoxChecked: Boolean; +begin + Result := FCheckBoxState = cbChecked; +end; + +function TKGridCellPainter.GetSortArrowWidth: Integer; +begin + if FSortArrow <> nil then + begin + if FState * [gdColsSortedDown, gdColsSortedUp] <> [] then + Result := FSortArrow.Height + 3 + else if FState * [gdRowsSortedDown, gdRowsSortedUp] <> [] then + Result := FSortArrow.Width + 3 + else + Result := 0; + end else + Result := 0; +end; + +procedure TKGridCellPainter.Initialize; +begin + FAttributes := [taEndEllipsis]; + FBackColor := clWindow; + FButton := False; + FButtonPressed := False; + FCheckBox := False; + FCheckBoxHAlign := halLeft; + FCheckBoxHPadding := 2; + FCheckBoxVAlign := valCenter; + FCheckBoxVPadding := 2; + FCheckBoxState := cbUnchecked; + FGraphic := nil; + FGraphicDrawText := False; + FGraphicHAlign := halCenter; + FGraphicHPadding := 2; + FGraphicStretchMode := stmZoom; + FGraphicVAlign := valCenter; + FGraphicVPadding := 2; + FHAlign := halLeft; + FHotFrameOnly := False; + FHPadding := 2; + FSortArrowHAlign := halRight; + FSortArrowHPadding := 2; + FText := ''; + FVAlign := valCenter; + FVPadding := 0; +end; + +procedure TKGridCellPainter.SetCheckBox(AValue: Boolean); +begin + if AValue <> FCheckBox then + begin + FCheckBox := AValue; + if AValue then + begin + // set default padding for check box text (not tested for Linux and MAC) + if FGrid.Themes then + FHPadding := 3 + else + FHPadding := 4; + end; + end; +end; + +procedure TKGridCellPainter.SetCheckBoxChecked(const Value: Boolean); +begin + if Value then + FCheckBoxState := cbChecked + else + FCheckBoxState := cbUnchecked; +end; + +{ TKGridColors } + +constructor TKGridColors.Create(AGrid: TKCustomGrid); +begin + inherited Create; + FGrid := AGrid; + FBrightRangeBkgnd := True; + Initialize; + ClearBrightColors; + //BrightRangeBkGnds; +end; + +procedure TKGridColors.Assign(Source: TPersistent); +begin + inherited; + if Source is TKGridColors then + begin + Colors := TKGridColors(Source).Colors; + FGrid.Invalidate; + end +end; + +procedure TKGridColors.BrightRangeBkGnds; + procedure DoBright(Src: TColor; var Dest: TColor); + begin + Dest := BrightColor(Src, 0.4, bsOfTop); + end; +begin + if FBrightRangeBkGnd and (FGrid.ComponentState * [csDesigning, csLoading] = []) then + begin + DoBright(FColors[ciFocusedCellBkGnd], FColors[ciFocusedRangeBkGnd]); + DoBright(FColors[ciSelectedCellBkGnd], FColors[ciSelectedRangeBkGnd]); + end; +end; + +procedure TKGridColors.ClearBrightColors; +var + I: TKGridColorIndex; +begin + for I := 0 to Length(FBrightColors) - 1 do + FBrightColors[I] := clNone; +end; + +function TKGridColors.GetColor(Index: TKGridColorIndex): TColor; +begin + Result := InternalGetColor(Index); +end; + +function TKGridColors.GetColorEx(Index: TKGridColorIndex): TColor; +begin + Result := FColors[Index]; +end; + +procedure TKGridColors.Initialize; +begin + SetLength(FColors, ciGridColorsMax + 1); + SetLength(FBrightColors, ciGridColorsMax + 1); + FColors[ciCellBkGnd] := cCellBkGndDef; + FColors[ciCellLines] := cCellLinesDef; + FColors[ciCellText] := cCellTextDef; + FColors[ciDragSuggestionBkGnd] := cDragSuggestionBkGndDef; + FColors[ciDragSuggestionLine] := cDragSuggestionLineDef; + FColors[ciFixedCellBkGnd] := cFixedCellBkGndDef; + FColors[ciFixedCellIndication] := cFixedCellIndicationDef; + FColors[ciFixedCellLines] := cFixedCellLinesDef; + FColors[ciFixedCellText] := cFixedCellTextDef; + FColors[ciFixedThemedCellLines] := cFixedThemedCellLinesDef; + FColors[ciFixedThemedCellHighlight] := cFixedThemedCellHighlightDef; + FColors[ciFixedThemedCellShadow] := cFixedThemedCellShadowDef; + FColors[ciFocusedCellBkGnd] := cFocusedCellBkGndDef; + FColors[ciFocusedCellText] := cFocusedCellTextDef; + FColors[ciFocusedRangeBkGnd] := cFocusedRangeBkGndDef; + FColors[ciFocusedRangeText] := cFocusedRangeTextDef; + FColors[ciSelectedCellBkGnd] := cSelectedCellBkGndDef; + FColors[ciSelectedCellText] := cSelectedCellTextDef; + FColors[ciSelectedRangeBkGnd] := cSelectedRangeBkGndDef; + FColors[ciSelectedRangeText] := cSelectedRangeTextDef; + // aki: + FColors[ciSelectedFixedCellBkGnd] := cSelectedFixedCellBkGndDef; +end; + +function TKGridColors.InternalGetColor(Index: TKGridColorIndex): TColor; +begin + case FColorScheme of + csBright: + begin + if FBrightColors[Index] = clNone then + FBrightColors[Index] := BrightColor(FColors[Index], 0.5, bsOfTop); + Result := FBrightColors[Index]; + end; + csGrayed: + case Index of + ciCellBkGnd, ciFocusedCellText, ciSelectedCellText: Result := clWindow; + ciCellText, ciFixedCellText, ciFocusedCellBkGnd: Result := clGrayText; + else + Result := FColors[Index]; + end; + csGrayScale: + Result := ColorToGrayScale(FColors[Index]); + else + Result := FColors[Index]; + end; +end; + +procedure TKGridColors.InternalSetColor(Index: TKGridColorIndex; Value: TColor); +begin + if FColors[Index] <> Value then + begin + FColors[Index] := Value; + FBrightColors[Index] := clNone; + if not (csLoading in FGrid.ComponentState) then + FGrid.Invalidate; + end; +end; + +procedure TKGridColors.SetColor(Index: TKGridColorIndex; Value: TColor); +begin + InternalSetColor(Index, Value); +end; + +procedure TKGridColors.SetColorEx(Index: TKGridColorIndex; Value: TColor); +begin + if FColors[Index] <> Value then + begin + FColors[Index] := Value; + FBrightColors[Index] := clNone; + end; +end; + +procedure TKGridColors.SetColors(const Value: TKColorArray); +var + I: Integer; +begin + for I := 0 to Min(Length(FColors), Length(Value)) - 1 do + FColors[I] := Value[I]; + ClearBrightColors; + BrightRangeBkGnds; +end; + +{ TKCustomGrid } + +constructor TKCustomGrid.Create(AOwner: TComponent); +const + GridStyle = [csCaptureMouse, csDoubleClicks, csOpaque]; +begin + inherited; + if NewStyleControls then + ControlStyle := GridStyle + else + ControlStyle := GridStyle + [csFramed]; +{$IFDEF FPC} + FFlat := False; +{$ENDIF} + FCellHintTimer := TTimer.Create(Self); + FCellHintTimer.Enabled := False; + FCellHintTimer.Interval := cMouseCellHintTimeDef; + FCellHintTimer.OnTimer := CellHintTimerHandler; + FCells := nil; + FCellClass := TKGridTextCell; + FCellPainterClass := TKGridCellPainter; + FCellPainter := FCellPainterClass.Create(Self); + FColClass := TKGridCol; + FColCount := cInvalidIndex; + FCols := nil; + FColors := TKGridColors.Create(Self); + FDefaultColWidth := cDefaultColWidthDef; + FDefaultRowHeight := cDefaultRowHeightDef; + FDisabledDrawStyle := cDisabledDrawStyleDef; + FDragArrow := TKAlphaBitmap.CreateFromRes('KGRID_DRAG_ARROW'); + FDragWindow := nil; + FDragStyle := dsLayeredFaded; + FEditedCell := nil; + FEditor := nil; + FEditorCell := GridPoint(-1, -1); + FEditorTransparency := cEditorTransparencyDef; + FFixedCols := cInvalidIndex; + FFixedRows := cInvalidIndex; + FGridLineWidth := cGridLineWidthDef; + FGridState := gsNormal; + FHCI.HBegin := TKAlphaBitmap.CreateFromRes('KGRID_HCI_HBEGIN'); + FHCI.HCenter := TKAlphaBitmap.CreateFromRes('KGRID_HCI_HCENTER'); + FHCI.HEnd := TKAlphaBitmap.CreateFromRes('KGRID_HCI_HEND'); + FHCI.VBegin := TKAlphaBitmap.CreateFromRes('KGRID_HCI_VBEGIN'); + FHCI.VCenter := TKAlphaBitmap.CreateFromRes('KGRID_HCI_VCENTER'); + FHCI.VEnd := TKAlphaBitmap.CreateFromRes('KGRID_HCI_VEND'); + FMaxCol := cInvalidIndex; + FMaxRow := cInvalidIndex; + FMemCol := cInvalidIndex; + FMemRow := cInvalidIndex; + FMinColWidth := cMinColWidthDef; + FMinRowHeight := cMinRowHeightDef; + FMouseCellHintTime := cMouseCellHintTimeDef; + FMouseOver := GridPoint(-1, -1); + FMoveDirection := cMoveDirectionDef; + FOptions := cOptionsDef; + FOptionsEx := cOptionsExDef; + FRangeSelectStyle := cRangeSelectStyleDef; + FRowClass := TKGridRow; + FRowCount := cInvalidIndex; + FRows := nil; + FScrollBars := cScrollBarsDef; + FScrollModeHorz := cScrollModeDef; + FScrollModeVert := cScrollModeDef; + FScrollOffset := Point(0, 0); + FScrollSpeed := cScrollSpeedDef; + FScrollTimer := TTimer.Create(Self); + FScrollTimer.Enabled := False; + FScrollTimer.Interval := FScrollSpeed; + FScrollTimer.OnTimer := ScrollTimerHandler; + FSelections := nil; + FSizingStyle := cSizingStyleDef; + FSortStyle := cSortStyleDef; + FSortModeLock := 0; + FTmpBitmap := TBitmap.Create; + FTmpBitmap.Width := 1; + FTmpBitmap.Height := 1; + FTopLeft := GridPoint(cInvalidIndex, cInvalidIndex); + FOnBeginColDrag := nil; + FOnBeginColSizing := nil; + FOnBeginRowDrag := nil; + FOnBeginRowSizing := nil; + FOnCellSpan := nil; + FOnChanged := nil; + FOnCheckColDrag := nil; + FOnCheckRowDrag := nil; + FOnColMoved := nil; + FOnColWidthsChanged := nil; + FOnColWidthsChangedEx := nil; + FOnCompareCellInstances := nil; + FOnCompareCells := nil; + FOnCustomSortCols := nil; + FOnCustomSortRows := nil; + FOnDrawCell := nil; + FOnEditorCreate := nil; + FOnEditorDataFromGrid := nil; + FOnEditorDataToGrid := nil; + FOnEditorDestroy := nil; + FOnEditorKeyPreview := nil; + FOnEditorResize := nil; + FOnEndColDrag := nil; + FOnEndColSizing := nil; + FOnEndRowDrag := nil; + FOnEndRowSizing := nil; + FOnExchangeCols := nil; + FOnExchangeRows := nil; + FOnMeasureCell := nil; + FOnMouseCellHint := nil; + FOnMouseClickCell := nil; + FOnMouseDblClickCell := nil; + FOnMouseEnterCell := nil; + FOnMouseLeaveCell := nil; + FOnRowHeightsChanged := nil; + FOnRowMoved := nil; + FOnSelectCell := nil; + FOnSizeChanged := nil; + FOnTopLeftChanged := nil; + Color := clWindow; + LoadCustomCursor(crHResize, 'KGRID_CURSOR_HRESIZE'); + LoadCustomCursor(crVResize, 'KGRID_CURSOR_VRESIZE'); + ParentColor := False; + TabStop := True; + ChangeDataSize(True, 0, cColCountDef, True, 0, cRowCountDef); + SetBounds(Left, Top, FColCount * FDefaultColWidth, + FRowCount * FDefaultRowHeight); +end; + +destructor TKCustomGrid.Destroy; +begin + EditorMode := False; + inherited Destroy; + FHint.Free; + FCellPainter.Free; + FColors.Free; + FEditedCell.Free; + FDragArrow.Free; + FDragWindow.Free; + FHCI.HBegin.Free; + FHCI.HCenter.Free; + FHCI.HEnd.Free; + FHCI.VBegin.Free; + FHCI.VCenter.Free; + FHCI.VEnd.Free; + FTmpBitmap.Free; + FreeData; +end; + +procedure TKCustomGrid.AdjustPageSetup; +begin + inherited; + PageSetup.PrintingMapped := True; +end; + +function TKCustomGrid.AdjustSelection(const ASelection: TKGridRect): TKGridRect; +begin + Result := ASelection; + if goRowSelect in FOptions then + begin + // aki: + if gxEditFixedCols in FOptionsEx then + begin + Result.Col1:=0; + Result.Col2:=FColCount - 1; + end else + begin + Result.Col1 := FFixedCols; + Result.Col2 := FColCount - 1; + end; + end; +end; + +procedure TKCustomGrid.AutoSizeCol(ACol: Integer; FixedCells: Boolean); +var + R: TRect; + Dummy, Extent, FirstRow, I, MaxExtent: Integer; + Span: TKGridCellSpan; + GridFocused: Boolean; +begin + if ColValid(ACol) then + begin + GridFocused := HasFocus; + R.Left := 0; + R.Top := 0; + MaxExtent := FMinColWidth; + Extent := InternalGetColWidths(ACol); + if FixedCells then FirstRow := 0 else FirstRow := FFixedRows; + for I := FirstRow to FRowCount - 1 do + begin + Span := InternalGetCellSpan(ACol, I); + if (Span.RowSpan > 0) and (Span.ColSpan > 0) then + begin + InternalGetHExtent(ACol, Span.ColSpan, R.Right, Dummy); + InternalGetVExtent(I, Span.RowSpan, R.Bottom, Dummy); + MaxExtent := Max(MaxExtent, MeasureCell(ACol, I, R, GetDrawState(ACol, I, GridFocused), mpColWidth).X - R.Right + Extent); + end; + end; + ColWidths[ACol] := MaxExtent; + end; +end; + +procedure TKCustomGrid.AutoSizeGrid(Priority: TKGridMeasureCellPriority; FixedCells: Boolean); +var + R: TRect; + CellExtent: TPoint; + Dummy, Extent, FirstCol, FirstRow, I, J, MaxExtent: Integer; + Span: TKGridCellSpan; + ModifyCols, ModifyRows, GridFocused: Boolean; + ColMaxExtents: TDynIntegers; +begin + LockUpdate; + try + { Despite the update lock, this function is rather slow for huge grids, + of course, because it has to measure all cells. } + GridFocused := HasFocus; + MaxExtent := 0; + Extent := 0; + R.Left := 0; + R.Top := 0; + if FixedCells then FirstCol := 0 else FirstCol := FFixedCols; + if FixedCells then FirstRow := 0 else FirstRow := FFixedRows; + ModifyCols := Priority in [mpColWidth, mpCellExtent]; + ModifyRows := Priority in [mpRowHeight, mpCellExtent]; + if ModifyCols then + begin + SetLength(ColMaxExtents, FColCount - FirstCol); + for I := 0 to FColCount - FirstCol - 1 do + ColMaxExtents[I] := FMinColWidth; + end; + for J := FirstRow to FRowCount - 1 do + begin + if ModifyRows then + begin + MaxExtent := 0; + Extent := InternalGetRowHeights(J); + end; + for I := FirstCol to FColCount - 1 do + begin + Span := InternalGetCellSpan(I, J); + if (Span.RowSpan > 0) and (Span.ColSpan > 0) then + begin + InternalGetHExtent(I, Span.ColSpan, R.Right, Dummy); + InternalGetVExtent(J, Span.RowSpan, R.Bottom, Dummy); + CellExtent := MeasureCell(I, J, R, GetDrawState(I, J, GridFocused), Priority); + if ModifyRows then + MaxExtent := Max(MaxExtent, CellExtent.Y - R.Bottom + Extent); + if ModifyCols then + ColMaxExtents[I - FirstCol] := Max(ColMaxExtents[I - FirstCol], CellExtent.x - R.Right + InternalGetColWidths(I)); + end; + end; + if ModifyRows then + RowHeights[J] := MaxExtent; + end; + if ModifyCols then + for I := FirstCol to FColCount - 1 do + ColWidths[I] := ColMaxExtents[I - FirstCol]; + finally + UnlockUpdate; + end; +end; + +procedure TKCustomGrid.AutoSizeRow(ARow: Integer; FixedCells: Boolean); +var + R: TRect; + Dummy, Extent, FirstCol, I, MaxExtent: Integer; + Span: TKGridCellSpan; + GridFocused: Boolean; +begin + if RowValid(ARow) then + begin + GridFocused := HasFocus; + R.Left := 0; + R.Top := 0; + MaxExtent := FMinRowHeight; + Extent := InternalGetRowHeights(ARow); + if FixedCells then FirstCol := 0 else FirstCol := FFixedCols; + for I := FirstCol to FColCount - 1 do + begin + Span := InternalGetCellSpan(I, ARow); + if (Span.RowSpan > 0) and (Span.ColSpan > 0) then + begin + InternalGetHExtent(I, Span.ColSpan, R.Right, Dummy); + InternalGetVExtent(ARow, Span.RowSpan, R.Bottom, Dummy); + MaxExtent := Max(MaxExtent, MeasureCell(I, ARow, R, GetDrawState(I, ARow, GridFocused), mpRowHeight).Y - R.Bottom + Extent); + end; + end; + RowHeights[ARow] := MaxExtent; + end; +end; + +function TKCustomGrid.BeginColDrag(var Origin: Integer; + const MousePt: TPoint): Boolean; +begin + Result := True; + if Assigned(FOnBeginColDrag) then + FOnBeginColDrag(Self, Origin, MousePt, Result) + else if Assigned(FCols) then + FCols[Origin].BeginDrag(Origin, MousePt, Result); + Origin := MinMax(Origin, FFixedCols, FColCount - 1); +end; + +function TKCustomGrid.BeginColSizing(var Index, Pos: Integer): Boolean; +begin + Result := True; + if Assigned(FOnBeginColSizing) then + FOnBeginColSizing(Self, Index, Pos, Result) + else if Assigned(FCols) then + Result := FCols[Index].CanResize; + Index := MinMax(Index, 0, FColCount - 1); +end; + +function TKCustomGrid.BeginRowDrag(var Origin: Integer; + const MousePt: TPoint): Boolean; +begin + Result := True; + if Assigned(FOnBeginRowDrag) then + FOnBeginRowDrag(Self, Origin, MousePt, Result) + else if Assigned(FRows) then + FRows[Origin].BeginDrag(Origin, MousePt, Result); + Origin := MinMax(Origin, FFixedRows, FRowCount - 1); +end; + +function TKCustomGrid.BeginRowSizing(var Index, Pos: Integer): Boolean; +begin + Result := True; + if Assigned(FOnBeginRowSizing) then + FOnBeginRowSizing(Self, Index, Pos, Result) + else if Assigned(FRows) then + Result := FRows[Index].CanResize; + Index := MinMax(Index, 0, FRowCount - 1); +end; + +procedure TKCustomGrid.CancelMode; +begin + try + case FGridState of + gsColSizing, gsRowSizing: + SuggestSizing(csStop); + gsColMoving, gsRowMoving: + begin + ProcessDragWindow(FHitPos, Point(0, 0), cInvalidIndex, FGridState = gsColMoving, True); + SuggestDrag(csStop); + end; + else + InvalidateCell(FHitCell.Col, FHitCell.Row); + end; + finally + MouseCapture := False; + FGridState := gsNormal; + end; +end; + +procedure TKCustomGrid.CellHintTimerHandler(Sender: TObject); +begin + if (FMouseOver.Col = FHintCell.Col) and (FMouseOver.Row = FHintCell.Row) then + MouseCellHint(FMouseOver.Col, FMouseOver.Row, True); + FCellHintTimer.Enabled := False; +end; + +function TKCustomGrid.CellRect(ACol, ARow: Integer; out R: TRect; + VisibleOnly: Boolean): Boolean; +var + I, W, H: Integer; + Span: TKGridCellSpan; +begin + Result := False; + if ColValid(ACol) and RowValid(ARow) then + begin + Span := InternalGetCellSpan(ACol, ARow); + if (Span.ColSpan <= 0) or (Span.RowSpan <= 0) then + Span := MakeCellSpan(1, 1); + if CellToPoint(ACol, ARow, R.TopLeft, VisibleOnly) then + begin + W := 0; + for I := ACol to ACol + Span.ColSpan - 1 do + Inc(W, InternalGetColWidths(I) + InternalGetEffectiveColSpacing(I)); + H := 0; + for I := ARow to ARow + Span.RowSpan - 1 do + Inc(H, InternalGetRowHeights(I) + InternalGetEffectiveRowSpacing(I)); + if ACol >= FFixedCols then + begin + if goVertLine in FOptions then Dec(W, FGridLineWidth); + end else + if goFixedVertLine in FOptions then Dec(W, FGridLineWidth); + if ARow >= FFixedRows then + begin + if goHorzLine in FOptions then Dec(H, FGridLineWidth); + end else + if goFixedHorzLine in FOptions then Inc(H, FGridLineWidth); + if (W > 0) and (H > 0) then + begin + R.Right := R.Left + W; + R.Bottom := R.Top + H; + Result := True; + end; + end; + end; +end; + +function TKCustomGrid.CellSelected(ACol, ARow: Integer): Boolean; +begin + Result := CellInGridRect(ACol, ARow, Selection); +end; + +function TKCustomGrid.CellToPoint(ACol, ARow: Integer; var Point: TPoint; + VisibleOnly: Boolean): Boolean; + + function Axis(const Info: TKGridAxisInfo; Cell: Integer; out Coord: Integer): Boolean; + var + I: Integer; + begin + Result := False; + if (Cell >= 0) and (Cell < Info.TotalCellCount) then + begin + I := 0; + Coord := 0; + while (I < Cell) and (I < Info.FixedCellCount) and (not VisibleOnly or (Coord < Info.ClientExtent)) do + begin + Inc(Coord, Info.CellExtent(I) + Info.EffectiveSpacing(I)); + Inc(I); + end; + if not VisibleOnly or (Coord < Info.ClientExtent) then + begin + if I = Info.FixedCellCount then + begin + Dec(Coord, Info.ScrollOffset); + I := Info.FirstGridCell; + while not VisibleOnly and (Cell < I) and (I > Info.FixedCellCount) do + begin + Dec(I); + Dec(Coord, Info.CellExtent(I) + Info.EffectiveSpacing(I)); + end; + while (I < Cell) and (I < Info.TotalCellCount) and (not VisibleOnly or (Coord < Info.ClientExtent)) do + begin + Inc(Coord, Info.CellExtent(I) + Info.EffectiveSpacing(I)); + Inc(I); + end; + end; + Result := Cell = I; + if Result then + begin + while (I >= 0) and (Info.CellExtent(I) = 0) do Dec(I); + if I < Cell - 1 then + Dec(Coord, Info.EffectiveSpacing(I + 1)); + end; + end; + end; + end; + +begin + if ColValid(ACol) and RowValid(ARow) then + begin + Result := Axis(GetAxisInfoHorz([]), ACol, Point.X); + if Result then + Result := Axis(GetAxisInfoVert([]), ARow, Point.Y); + end else + Result := False; +end; + +function TKCustomGrid.CellVisible(ACol, ARow: Integer): Boolean; +begin + Result := CellInGridRect(ACol, ARow, VisibleGridRect); +end; + +procedure TKCustomGrid.Changed; +begin + if Assigned(FOnChanged) then + FOnChanged(Self, FEditorCell.Col, FEditorCell.Row); +end; + +procedure TKCustomGrid.ChangeDataSize(ColInsert: Boolean; ColAt, ColCnt: Integer; + RowInsert: Boolean; RowAt, RowCnt: Integer); + + procedure Axis(var Data: TKGridAxisItems; AxisItemClass: TKGridAxisItemClass; + Insert: Boolean; DefFixedCnt: Integer; var At, Cnt, MaxLen, ItemCount, FixedCount: Integer); + var + I, Len: Integer; + begin + if Cnt > 0 then + begin + Len := Length(Data); + if Insert then + begin + At := MinMax(At, 0, Len); + SetLength(Data, Len + Cnt); + for I := Len - 1 downto At do Data[I + Cnt] := Data[I]; + for I := At to At + Cnt - 1 do + begin + Data[I] := AxisItemClass.Create(Self); + Data[I].InitialPos := MaxLen + 1; + Inc(MaxLen); + end; + if FixedCount < 0 then + FixedCount := DefFixedCnt + else if At < FixedCount then + Inc(FixedCount, Cnt); + end + else if Len > 0 then + begin + At := MinMax(At, 0, Len - 1); + Cnt := Min(Cnt, Len - At); + if Cnt > 0 then + begin + for I := At to At + Cnt - 1 do + Data[I].Free; + for I := At to Len - Cnt - 1 do Data[I] := Data[I + Cnt]; + SetLength(Data, Len - Cnt); + if At < FixedCount then + Dec(FixedCount, FixedCount - At); + end; + end; + ItemCount := Length(Data); + FixedCount := Min(FixedCount, ItemCount - 1); + end; + end; + +var + OldFixedRows, OldFixedCols, I, J, Len: Integer; + UpdateNeeded: Boolean; + Reason: TKGridSizeChange; +begin + EditorMode := False; + UpdateNeeded := False; + if not ColInsert then + ColCnt := Min(ColCnt, FColCount - 1); + if not RowInsert then + RowCnt := Min(RowCnt, FRowCount - 1); + OldFixedCols := FFixedCols; + Axis(FCols, FColClass, ColInsert, cFixedColsDef, + ColAt, ColCnt, FMaxCol, FColCount, FFixedCols); + OldFixedRows := FFixedRows; + Axis(FRows, FRowClass, RowInsert, cFixedRowsDef, + RowAt, RowCnt, FMaxRow, FRowCount, FFixedRows); + FMemCol := cInvalidIndex; + FMemRow := cInvalidIndex; + if goVirtualGrid in FOptions then + begin + if Assigned(FCells) then + begin + for I := 0 to Length(FCells) - 1 do + for J := 0 to Length(FCells[I]) - 1 do + FCells[I, J].Free; + FCells := nil; + UpdateNeeded := True; + end; + end else + begin + // take rows first because probably there will be always much more rows + if RowCnt > 0 then + begin + Len := Length(FCells); + if FRowCount > Len then + begin + SetLength(FCells, Len + RowCnt); + for I := Len - 1 downto RowAt do FCells[I + RowCnt] := FCells[I]; + for I := RowAt to RowAt + RowCnt - 1 do + begin + SetLength(FCells[I], FColCount); + for J := 0 to Length(FCells[I]) - 1 do FCells[I, J] := nil; + end; + end else + begin + for I := RowAt to RowAt + RowCnt - 1 do + begin + for J := 0 to Length(FCells[I]) - 1 do FCells[I, J].Free; + FCells[I] := nil; + end; + for I := RowAt to Len - RowCnt - 1 do FCells[I] := FCells[I + RowCnt]; + SetLength(FCells, Len - RowCnt); + end; + end; + if ColCnt > 0 then + begin + for I := 0 to Length(FCells) - 1 do + begin + Len := Length(FCells[I]); + if FColCount > Len then + begin + SetLength(FCells[I], Len + ColCnt); + for J := Len - 1 downto ColAt do FCells[I, J + ColCnt] := FCells[I, J]; + for J := ColAt to ColAt + ColCnt - 1 do FCells[I, J] := nil; + end + else if FColCount < Len then + begin + for J := ColAt to ColAt + ColCnt - 1 do FCells[I, J].Free; + for J := ColAt to Len - ColCnt - 1 do FCells[I, J] := FCells[I, J + ColCnt]; + SetLength(FCells[I], Len - ColCnt); + end; + end; + end; + end; + if (ColCnt > 0) or (RowCnt > 0) then + begin + SelectionFix(FSelection); + if (FFixedRows <> OldFixedRows) or (FFixedCols <> OldFixedCols) then + ResetTopLeft; + UpdateAxes(ColCnt > 0, cAll, RowCnt > 0, cAll, []); + UpdateCellSpan; + if ColCnt > 0 then + begin + if ColInsert then + begin + ClearSortModeVert; + Reason := scColInserted; + end else + Reason := scColDeleted; + SizeChanged(Reason, ColAt, ColCnt); + end; + if RowCnt > 0 then + begin + if RowInsert then + begin + ClearSortModeHorz; + Reason := scRowInserted + end else + Reason := scRowDeleted; + SizeChanged(Reason, RowAt, RowCnt); + end; + end else if UpdateNeeded then + Invalidate; +end; + +function TKCustomGrid.CheckColDrag(Origin: Integer; var Destination: Integer; + const MousePt: TPoint): Boolean; +begin + Result := True; + if Assigned(FOnCheckColDrag) then + FOnCheckColDrag(Self, Origin, Destination, MousePt, Result) + else if Assigned(FCols) then + FCols[Destination].CheckDrag(Origin, Destination, MousePt, Result); + Destination := MinMax(Destination, FFixedCols, FColCount - 1); +end; + +function TKCustomGrid.CheckRowDrag(Origin: Integer; var Destination: Integer; + const MousePt: TPoint): Boolean; +begin + Result := True; + if Assigned(FOnCheckRowDrag) then + FOnCheckRowDrag(Self, Origin, Destination, MousePt, Result) + else if Assigned(FRows) then + FRows[Destination].CheckDrag(Origin, Destination, MousePt, Result); + Destination := MinMax(Destination, FFixedRows, FRowCount - 1); +end; + +function TKCustomGrid.ClampInView(ACol, ARow: Integer): Boolean; +var + DeltaHorz, DeltaVert: Integer; +begin + Result := ScrollNeeded(ACol, ARow, DeltaHorz, DeltaVert); + if Result then + Scroll(cScrollDelta, cScrollDelta, DeltaHorz, DeltaVert, True); +end; + +procedure TKCustomGrid.ClearCol(ACol: Integer); +var + I: Integer; +begin + if Assigned(FCells) and ColValid(ACol) then + begin + for I := 0 to FRowCount - 1 do + FreeAndNil(FCells[I, ACol]); + UpdateCellSpan; + InvalidateCol(ACol); + end; +end; + +procedure TKCustomGrid.ClearGrid; +var + I, J: Integer; +begin + if Assigned(FCells) then + begin + for I := 0 to FColCount - 1 do + for J := 0 to FRowCount - 1 do + FreeAndNil(FCells[J, I]); + UpdateCellSpan; + Invalidate; + end; +end; + +procedure TKCustomGrid.ClearRow(ARow: Integer); +var + I: Integer; +begin + if Assigned(FCells) and RowValid(ARow) then + begin + for I := 0 to FColCount - 1 do + FreeAndNil(FCells[ARow, I]); + UpdateCellSpan; + InvalidateRow(ARow); + end; +end; + +procedure TKCustomGrid.ClearSortMode; +begin + ClearSortModeHorz; + ClearSortModeVert; +end; + +procedure TKCustomGrid.ClearSortModeHorz; +var + OldIndex: Integer; +begin + if SortModeUnlocked then + begin + OldIndex := SortCol; + if OldIndex >= 0 then + begin + FlagSet(cGF_GridUpdates); + try + FCols[OldIndex].SortMode := smNone; + finally + FlagClear(cGF_GridUpdates); + end; + InvalidateGridRect(GridRect(OldIndex, 0, OldIndex, FFixedRows - 1)); + end; + end; +end; + +procedure TKCustomGrid.ClearSortModeVert; +var + OldIndex: Integer; +begin + if SortModeUnlocked then + begin + OldIndex := SortRow; + if OldIndex >= 0 then + begin + FlagSet(cGF_GridUpdates); + try + FRows[OldIndex].SortMode := smNone; + finally + FlagClear(cGF_GridUpdates); + end; + InvalidateGridRect(GridRect(0, OldIndex, FFixedCols - 1, OldIndex)); + end; + end; +end; + +procedure TKCustomGrid.CMDesignHitTest(var Msg: TLMMouse); +begin + Msg.Result := Integer(Flag(cGF_DesignHitTest)); +end; + +procedure TKCustomGrid.CMEnabledChanged(var Msg: TLMessage); +begin + inherited; + if not Enabled then EditorMode := False; + Invalidate; +end; + +procedure TKCustomGrid.CMShowingChanged(var Msg: TLMessage); +begin + inherited; + if Showing then + UpdateScrollRange(True, True, False); +end; + +procedure TKCustomGrid.CMSysColorChange(var Msg: TLMessage); +begin + inherited; + FColors.ClearBrightColors; +end; + +procedure TKCustomGrid.CMVisibleChanged(var Msg: TLMessage); +begin + inherited; + if not Visible then + EditorMode := False; +end; + +procedure TKCustomGrid.CMWantSpecialKey(var Msg: TLMKey); +begin + inherited; + if (goEditing in Options) and (Msg.CharCode in [VK_RETURN, VK_ESCAPE]) then + Msg.Result := 1; +end; + +procedure TKCustomGrid.ColMoved(FromIndex, ToIndex: Integer); +begin + if Assigned(FOnColMoved) then + FOnColMoved(Self, FromIndex, ToIndex); +end; + +function TKCustomGrid.ColSelectable(ACol: Integer): Boolean; +begin + Result := (ACol >= FFixedCols) and (ACol < FColCount); +end; + +function TKCustomGrid.ColSelected(ACol: Integer): Boolean; +begin + Result := ColInGridRect(ACol, Selection); +end; + +function TKCustomGrid.ColValid(ACol: Integer): Boolean; +begin + Result := (ACol >= 0) and (ACol < FColCount); +end; + +procedure TKCustomGrid.ColWidthsChanged(ACol: Integer); +begin + if Assigned(FOnColWidthsChanged) then + FOnColWidthsChanged(Self) + else if Assigned(FOnColWidthsChangedEx) then + FOnColWidthsChangedEx(Self, ACol); +end; + +function TKCustomGrid.CompareCellInstances(ACell1, ACell2: TKGridCell): Integer; +begin + if Assigned(FOnCompareCellInstances) then + Result := FOnCompareCellInstances(Self, ACell1, ACell2) + else if Assigned(FCells) then + Result := DefaultCompareCells(ACell1, ACell2) + else + Result := 0; +end; + +function TKCustomGrid.CompareCells(ACol1, ARow1, ACol2, ARow2: Integer): Integer; +begin + if Assigned(FOnCompareCells) then + Result := FOnCompareCells(Self, ACol1, ARow1, ACol2, ARow2) + else if Assigned(FCells) then + Result := DefaultCompareCells(InternalGetCell(ACol1, ARow1), InternalGetCell(ACol2, ARow1)) + else + Result := 0; +end; + +function TKCustomGrid.CompareCols(ARow, ACol1, ACol2: Integer): Integer; +begin + if Assigned(FOnCompareCells) then + Result := FOnCompareCells(Self, ACol1, ARow, ACol2, ARow) + else if Assigned(FCells) then + Result := DefaultCompareCells(InternalGetCell(ACol1, ARow), InternalGetCell(ACol2, ARow)) + else + Result := 0; +end; + +function TKCustomGrid.CompareRows(ACol, ARow1, ARow2: Integer): Integer; +begin + if Assigned(FOnCompareCells) then + Result := FOnCompareCells(Self, ACol, ARow1, ACol, ARow2) + else if Assigned(FCells) then + Result := DefaultCompareCells(InternalGetCell(ACol, ARow1), InternalGetCell(ACol, ARow2)) + else + Result := 0; +end; + +procedure TKCustomGrid.CreateParams(var Params: TCreateParams); +begin + inherited CreateParams(Params); + with Params do + begin + Style := Style or WS_TABSTOP or WS_CLIPCHILDREN or WS_CLIPSIBLINGS; + if HasHorzScrollBar then Style := Style or WS_HSCROLL; + if HasVertScrollBar then Style := Style or WS_VSCROLL; + end; +end; + +function TKCustomGrid.CustomSortCols(ByRow: Integer; + var SortMode: TKGridSortMode): Boolean; +begin + Result := False; + if Assigned(FOnCustomSortCols) then FOnCustomSortCols(Self, ByRow, SortMode, Result); +end; + +function TKCustomGrid.CustomSortRows(ByCol: Integer; + var SortMode: TKGridSortMode): Boolean; +begin + Result := False; + if Assigned(FOnCustomSortRows) then FOnCustomSortRows(Self, ByCol, SortMode, Result); +end; + +procedure TKCustomGrid.DefaultColWidthChanged; +var + I: Integer; +begin + FlagSet(cGF_GridUpdates); + try + for I := 0 to FColCount - 1 do FCols[I].Extent := FDefaultColWidth; + finally + FlagClear(cGF_GridUpdates); + end; + UpdateAxes(True, cAll, False, cAll, [afCheckMinExtent]); +end; + +procedure TKCustomGrid.DefaultComboKeyPreview(AEditor: TComboBox; + ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); +begin + if Key in [VK_RETURN, VK_ESCAPE, VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT] then + begin + if AEditor.DroppedDown then + IsGridKey := False; + end + else if AEditor.Style in [csSimple, csDropDown] then + begin + // we have a combo box with edit control + DoEditKeyPreview(StringLength(AEditor.Text), AEditor.SelStart, AEditor.SelLength, 1, False, True, True, + Key, ShiftState, IsGridKey); + end; +end; + +procedure TKCustomGrid.DefaultComboSelect(AEditor: TComboBox; SelectAll, + CaretToLeft: Boolean); +begin + if AEditor.Style in [csSimple, csDropDown] then + begin + // we have a combo box with edit control + if SelectAll then + AEditor.SelectAll + else + begin + AEditor.SelLength := 0; + if CaretToLeft then + AEditor.SelStart := 0 + else + AEditor.SelStart := StringLength(AEditor.Text); + end; + end; +end; + +procedure TKCustomGrid.DefaultEditKeyPreview(AEditor: TCustomEdit; + ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); +var + MultiLine, StartLine, EndLine: Boolean; + TextLen, LineCount: Integer; +begin + TextLen := StringLength(AEditor.Text); + if AEditor is TCustomMemo then + begin + MultiLine := True; + LineCount := TCustomMemo(AEditor).Lines.Count; + StartLine := AEditor.SelStart < StringLength(TCustomMemo(AEditor).Lines[0]); + EndLine := AEditor.SelStart > TextLen - StringLength(TCustomMemo(AEditor).Lines[TCustomMemo(AEditor).Lines.Count - 1]); + end else + begin + MultiLine := False; + StartLine := True; + EndLine := True; + LineCount := 1; + end; + DoEditKeyPreview(StringLength(AEditor.Text), AEditor.SelStart, AEditor.SelLength, LineCount, MultiLine, StartLine, EndLine, + Key, ShiftState, IsGridKey); +end; + +procedure TKCustomGrid.DefaultEditorCreate(ACol, ARow: Integer; + var AEditor: TWinControl); +begin + AEditor := TEdit.Create(nil); +end; + +procedure TKCustomGrid.DefaultEditorDataFromGrid(AEditor: TWinControl; + ACol, ARow: Integer; var AssignText: Boolean); +begin + // empty +end; + +procedure TKCustomGrid.DefaultEditorDataToGrid(AEditor: TWinControl; + ACol, ARow: Integer; var AssignText: Boolean); +begin + // empty +end; + +procedure TKCustomGrid.DefaultEditorDestroy(AEditor: TWinControl; ACol, + ARow: Integer); +begin + // empty +end; + +procedure TKCustomGrid.DefaultEditorKeyPreview(AEditor: TWinControl; + ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); +begin + if AEditor is TCustomEdit then + DefaultEditKeyPreview(TCustomEdit(AEditor), ACol, ARow, Key, ShiftState, IsGridKey) + else if AEditor is TCustomComboBox then + DefaultComboKeyPreview(TComboBox(AEditor), ACol, ARow, Key, ShiftState, IsGridKey) +end; + +procedure TKCustomGrid.DefaultEditorResize(AEditor: TWinControl; + ACol, ARow: Integer; var ARect: TRect); +begin + // empty +end; + +procedure TKCustomGrid.DefaultEditorSelect(AEditor: TWinControl; + ACol, ARow: Integer; SelectAll, CaretToLeft, SelectedByMouse: Boolean); +begin + if AEditor is TCustomEdit then + DefaultEditSelect(TCustomEdit(AEditor), SelectAll, CaretToLeft) + else if AEditor is TCustomComboBox then + DefaultComboSelect(TComboBox(AEditor), SelectAll, CaretToLeft); +end; + +procedure TKCustomGrid.DefaultEditSelect(AEditor: TCustomEdit; SelectAll, + CaretToLeft: Boolean); +begin + if SelectAll then + AEditor.SelectAll + else + begin + if CaretToLeft then + AEditor.SelStart := 0 + else + AEditor.SelStart := StringLength(AEditor.Text); + AEditor.SelLength := 0; + end; +end; + +function TKCustomGrid.DefaultCompareCells(ACell1, ACell2: TKGridCell): Integer; +var +{$IFDEF STRING_IS_UNICODE} + S1, S2: string; +{$ELSE} + W1, W2: PWideChar; +{$ENDIF} +begin +{$IFDEF STRING_IS_UNICODE} + if ACell1 is TKGridTextCell then S1 := TKGridTextCell(ACell1).Text else S1 := ''; + if ACell2 is TKGridTextCell then S2 := TKGridTextCell(ACell2).Text else S2 := ''; + Result := CompareStrings(S1, S2); +{$ELSE} + if ACell1 is TKGridTextCell then W1 := TKGridTextCell(ACell1).TextPtr else W1 := ''; + if ACell2 is TKGridTextCell then W2 := TKGridTextCell(ACell2).TextPtr else W2 := ''; + Result := CompareWideChars(W1, W2); +{$ENDIF} +end; + +procedure TKCustomGrid.DefaultMouseCellHint(ACol, ARow: Integer; + AShow: Boolean); +var + R: TRect; + Extent: TPoint; + AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; +begin + if ColValid(ACol) and Cols[ACol].CellHint then + begin + if AShow then + begin + AText := Cells[ACol, ARow]; + if (AText <> '') and (ARow >= FFixedRows) and + ((ARow <> FEditorCell.Row) or (ACol <> FEditorCell.Col) or not EditorMode) and + CellRect(ACol, ARow, R, True) then + begin + Extent := MeasureCell(ACol, ARow, R, GetDrawState(ACol, ARow, HasFocus), mpCellExtent); + if (Extent.X > R.Right - R.Left) or (Extent.Y > R.Bottom - R.Top) then + begin + FreeAndNil(FHint); + FHint := TKTextHint.Create(nil); + TKTextHint(FHint).Text := AText; + Inc(R.Left, 10); + Inc(R.Top, 10); + FHint.ShowAt(ClientToScreen(R.TopLeft)); + end; + end; + end else + FreeAndNil(FHint); + end else + FreeAndNil(FHint); +end; + +procedure TKCustomGrid.DefaultRowHeightChanged; +var + I: Integer; +begin + FlagSet(cGF_GridUpdates); + try + for I := 0 to FRowCount - 1 do FRows[I].Extent := FDefaultRowHeight; + finally + FlagClear(cGF_GridUpdates); + end; + UpdateAxes(False, cAll, True, cAll, [afCheckMinExtent]); +end; + +procedure TKCustomGrid.DefaultScrollBarKeyPreview(AEditor: TScrollBar; + ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); +begin + if (Key = VK_LEFT) and (AEditor.Position > AEditor.Min) or + (Key = VK_RIGHT) and (AEditor.Position < AEditor.Max) then + IsGridKey := False; +end; + +procedure TKCustomGrid.DefaultSetCaretToLeft(Key: Word; ShiftState: TShiftState); +begin + if (Key in [VK_DOWN, VK_NEXT]) or (Key in [VK_RIGHT, VK_END]) and (Col < FColCount - 1) then + FlagSet(cGF_CaretToLeft); +end; + +procedure TKCustomGrid.DefineProperties(Filer: TFiler); + + function DoColData: Boolean; + begin + if (Filer.Ancestor <> nil) and (Filer.Ancestor is TKCustomGrid) then + Result := not CompareAxisItems(TKCustomGrid(Filer.Ancestor).FCols, FCols) + else + Result := FCols <> nil; + end; + + function DoRowData: Boolean; + begin + if (Filer.Ancestor <> nil) and (Filer.Ancestor is TKCustomGrid) then + Result := not CompareAxisItems(TKCustomGrid(Filer.Ancestor).FRows, FRows) + else + Result := FRows <> nil; + end; + +begin + inherited; + with Filer do + begin + DefineProperty('ColWidths', ReadColWidths, WriteColWidths, DoColData); + DefineProperty('RowHeights', ReadRowHeights, WriteRowHeights, DoRowData); + end; +end; + +procedure TKCustomGrid.DeleteCol(At: Integer); +begin + DeleteCols(At, 1); +end; + +procedure TKCustomGrid.DeleteCols(At, Count: Integer); +begin + if ColValid(At) and (FColCount > 1) then + begin + Count := Min(Count, FColCount - Max(At, 1)); + ChangeDataSize(False, At, Count, False, 0, 0); + end; +end; + +procedure TKCustomGrid.DeleteRow(At: Integer); +begin + DeleteRows(At, 1); +end; + +procedure TKCustomGrid.DeleteRows(At, Count: Integer); +begin + if RowValid(At) and (FRowCount > 1) then + begin + Count := Min(Count, FRowCount - Max(At, 1)); + ChangeDataSize(False, 0, 0, False, At, Count); + end; +end; + +function TKCustomGrid.DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; +var + Key: Word; +begin + Result := inherited DoMouseWheelDown(Shift, MousePos); + if not Result then + begin + Key := VK_DOWN; + KeyDown(Key, []); + Result := True; + end; +end; + +function TKCustomGrid.DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; +var + Key: Word; +begin + Result := inherited DoMouseWheelUp(Shift, MousePos); + if not Result then + begin + Key := VK_UP; + KeyDown(Key, []); + Result := True; + end; +end; + +procedure TKCustomGrid.DragMove(ACol, ARow: Integer; MousePt: TPoint); +begin + case FGridState of + gsColMoving: if CheckColDrag(FDragOrigin, ACol, MousePt) and (FDragDest <> ACol) then + begin + SuggestDrag(csHide); + FDragDest := ACol; + SuggestDrag(csShow); + end; + gsRowMoving: if CheckRowDrag(FDragOrigin, ARow, MousePt) and (FDragDest <> ARow) then + begin + SuggestDrag(csHide); + FDragDest := ARow; + SuggestDrag(csShow); + end; + end; +end; + +function TKCustomGrid.DrawCell(ACol, ARow: Integer; ARect: TRect; + AState: TKGridDrawState): Boolean; +begin + Result := True; + if Assigned(FOnDrawCell) then + FOnDrawCell(Self, ACol, ARow, ARect, AState) + else if Assigned(FCells) then with InternalGetCell(ACol, ARow) do + begin + ApplyDrawProperties; + DrawCell(ACol, ARow, ARect, AState) + end else + Result := False; +end; + +function TKCustomGrid.EditorCreate(ACol, ARow: Integer): TWinControl; +begin + Result := nil; + if Assigned(FOnEditorCreate) then + FOnEditorCreate(Self, ACol, ARow, Result) + else if Assigned(FCells) then + InternalGetCell(ACol, ARow).EditorCreate(ACol, ARow, Result) + else + DefaultEditorCreate(ACol, ARow, Result); +end; + +procedure TKCustomGrid.EditorDataFromGrid(AEditor: TWinControl; ACol, ARow: Integer); +var + AssignText: Boolean; +begin + AssignText := True; + if Assigned(FOnEditorDataFromGrid) then + FOnEditorDataFromGrid(Self, AEditor, ACol, ARow, AssignText) + else if Assigned(FCells) then + InternalGetCell(ACol, ARow).EditorDataFromGrid(AEditor, ACol, ARow, AssignText) + else + DefaultEditorDataFromGrid(AEditor, ACol, ARow, AssignText); + if AssignText then + SetControlText(AEditor, Cells[ACol, ARow]); +end; + +procedure TKCustomGrid.EditorDataToGrid(AEditor: TWinControl; ACol, ARow: Integer); +var + AssignText: Boolean; +begin + AssignText := True; + if Assigned(FOnEditorDataToGrid) then + FOnEditorDataToGrid(Self, AEditor, ACol, ARow, AssignText) + else if Assigned(FCells) then + InternalGetCell(ACol, ARow).EditorDataToGrid(AEditor, ACol, ARow, AssignText) + else + DefaultEditorDataToGrid(AEditor, ACol, ARow, AssignText); + if AssignText then + Cells[ACol, ARow] := GetControlText(AEditor); +end; + +procedure TKCustomGrid.EditorDestroy(var AEditor: TWinControl; ACol, ARow: Integer); +begin + if Assigned(FOnEditorDestroy) then + FOnEditorDestroy(Self, AEditor, ACol, ARow) + else if Assigned(FCells) then + InternalGetCell(ACol, ARow).EditorDestroy(AEditor, ACol, ARow) + else + DefaultEditorDestroy(AEditor, ACol, ARow); +end; + +function TKCustomGrid.EditorIsTransparent: Boolean; +begin + Result := False; + if FEditorTransparency = etTransparent then + Result := True + else if FEditorTransparency = etDefault then + begin + { Default behavior. For example TCheckBox is not meant to be transparent + by VCL/LCL but from grid's point of view it should be. } + Result := + (FEditor is TCustomCheckBox) or + (FEditor is TRadioButton) or + (FEditor is TStaticText); + end; +end; + +function TKCustomGrid.EditorKeyPreview(AEditor: TWinControl; ACol, ARow: Integer; + var Key: Word; Shift: TShiftState): Boolean; +begin + Result := True; + if Assigned(FOnEditorKeyPreview) then + FOnEditorKeyPreview(Self, AEditor, ACol, ARow, Key, Shift, Result) + else if Assigned(FCells) then + InternalGetCell(ACol, ARow).EditorKeyPreview(AEditor, ACol, ARow, Key, Shift, Result) + else + DefaultEditorKeyPreview(AEditor, ACol, ARow, Key, Shift, Result); +end; + +procedure TKCustomGrid.EditorResize(AEditor: TWinControl; ACol, ARow: Integer; + var ARect: TRect); +begin + if Assigned(FOnEditorResize) then + FOnEditorResize(Self, AEditor, ACol, ARow, ARect) + else if Assigned(FCells) then + InternalGetCell(ACol, ARow).EditorResize(AEditor, ACol, ARow, ARect) + else + DefaultEditorResize(AEditor, ACol, ARow, ARect); +end; + +procedure TKCustomGrid.EditorSelect(AEditor: TWinControl; ACol, ARow: Integer; + SelectAll, CaretToLeft, SelectedByMouse: Boolean); +begin + if Assigned(FOnEditorSelect) then + FOnEditorSelect(Self, AEditor, ACol, ARow, SelectAll, CaretToLeft, SelectedByMouse) + else if Assigned(FCells) then + InternalGetCell(ACol, ARow).EditorSelect(AEditor, ACol, ARow, SelectAll, CaretToLeft, SelectedByMouse) + else + DefaultEditorSelect(AEditor, ACol, ARow, SelectAll, CaretToLeft, SelectedByMouse); +end; + +procedure TKCustomGrid.EditorWindowProc(var Msg: TLMessage); + + procedure PaintCellBackground(DC: HDC); + var + SaveIndex: Integer; + ACanvas: TCanvas; + R, TmpBlockRect: TRect; + begin + if CellRect(Col, Row, R) then + begin + ACanvas := TCanvas.Create; + SaveIndex := SaveDC(DC); + try + ACanvas.Handle := DC; + R := Rect(0, 0, R.Right - R.Left, R.Bottom - R.Top); + TmpBlockRect := SelectionRect; + OffsetRect(TmpBlockRect, -R.Left, -R.Top); + InternalPaintCell(Col, Row, GetDrawState(Col, Row, HasFocus), + R, TmpBlockRect, ACanvas, False, False); + FEditor.Brush.Color := ACanvas.Brush.Color; + finally + RestoreDC(DC, SaveIndex); + ACanvas.Free; + end; + end; + end; + + procedure GotFocus; + begin + InvalidateCurrentSelection; + end; + + procedure LostFocus; + begin + InvalidateCurrentSelection; + end; + +var + Key: Word; + Shift: TShiftState; + CallDefault: Boolean; + Form: TCustomForm; +begin + CallDefault := True; + case Msg.Msg of + CM_MOUSEENTER, CM_MOUSELEAVE: // not called if editor is captured + try + MouseOverCells; // some win32 error might popup here + except + end; + CN_CHAR: + ClampInView(FEditorCell.Col, FEditorCell.Row); + {$IFNDEF FPC} + CN_COMMAND: + if TWMCommand(Msg).Ctl = FEditor.Handle then + begin + case TWMCommand(Msg).NotifyCode of + CBN_KILLFOCUS, BN_KILLFOCUS, LBN_KILLFOCUS, EN_KILLFOCUS: LostFocus; + CBN_SETFOCUS, BN_SETFOCUS, EN_SETFOCUS: GotFocus; + end; + end; + {$ELSE} + LM_ERASEBKGND: + begin + if EditorIsTransparent then + begin + PaintCellBackground(TLMEraseBkGnd(Msg).DC); + CallDefault := False; + Msg.Result := 1; + end; + end; + {$ENDIF} + { CN_KEYDOWN is sent from TApplication.IsKeyMsg as 'preview' so this message + is used as KeyPreview. WM_KEYDOWN is not sent here by all inplace editors as + some of them might have another child window with input focus + (in such cases WM_KEYDOWN is sent directly to it). But if it is sent here + so let's decide if it can be processed by inplace editor, either. } + CN_KEYDOWN, LM_KEYDOWN: + begin + Key := TLMKey(Msg).CharCode; + Shift := KeyDataToShiftState(TLMKey(Msg).KeyData); + case Key of + VK_RETURN, VK_ESCAPE, VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, + VK_PRIOR, VK_NEXT, VK_HOME, VK_END, VK_TAB: + begin + if EditorKeyPreview(FEditor, FEditorCell.Col, FEditorCell.Row, Key, Shift) then + begin + DefaultSetCaretToLeft(Key, Shift); + if Msg.Msg = CN_KEYDOWN then + PostLateUpdate(Msg) + else + ClampInView(FEditorCell.Col, FEditorCell.Row); + if (Key <> VK_TAB) or (goTabs in FOptions) then + begin + CallDefault := False; + Msg.Result := 1; + end; + end; + end else + ClampInView(FEditorCell.Col, FEditorCell.Row); + end; + end; + LM_GETDLGCODE: if goTabs in FOptions then + Msg.Result := Msg.Result or DLGC_WANTTAB or DLGC_WANTARROWS; + LM_KILLFOCUS: + LostFocus; + LM_MOUSEMOVE: + begin + if Flag(cGF_ThroughClick) and (GetCaptureControl = FEditor) then + begin + if (FGridState = gsSelecting) and not PtInRect(FEditor.BoundsRect, ScreenToClient(Mouse.CursorPos)) then + begin + MouseCapture := True; + FlagClear(cGF_ThroughClick); + end; + MouseOverCells; + end; + end; + LM_LBUTTONUP: + begin + if Flag(cGF_ThroughClick) then + begin + FGridState := gsNormal; + FlagClear(cGF_ThroughClick); + end; + end; + LM_SETFOCUS: + begin + Form := GetParentForm(Self); + if Assigned(Form) and not (csDestroying in Form.ComponentState) then + GotFocus + else + CallDefault := False; // eat the message to avoid an exception in LCL (TForm.SetFocusedControl) + end; + end; + if CallDefault then + FEditorWindowProc(Msg); +end; + +function TKCustomGrid.EndColDrag(Origin, Destination: Integer; + const MousePt: TPoint): Boolean; +begin + Result := True; + if Assigned(FOnEndColDrag) then + FOnEndColDrag(Self, Origin, Destination, MousePt, Result) + else if Assigned(FCols) then + FCols[Destination].EndDrag(Origin, Destination, MousePt, Result) +end; + +function TKCustomGrid.EndColSizing(var Index, Pos: Integer): Boolean; +begin + Result := True; + if Assigned(FOnEndColSizing) then + FOnEndColSizing(Self, Index, Pos, Result); + Index := MinMax(Index, 0, FColCount - 1); +end; + +function TKCustomGrid.EndRowDrag(Origin, Destination: Integer; + const MousePt: TPoint): Boolean; +begin + Result := True; + if Assigned(FOnEndRowDrag) then + FOnEndRowDrag(Self, Origin, Destination, MousePt, Result) + else if Assigned(FRows) then + FRows[Destination].EndDrag(Origin, Destination, MousePt, Result) +end; + +function TKCustomGrid.EndRowSizing(var Index, Pos: Integer): Boolean; +begin + Result := True; + if Assigned(FOnEndRowSizing) then + FOnEndRowSizing(Self, Index, Pos, Result); + Index := MinMax(Index, 0, FRowCount - 1); +end; + +procedure TKCustomGrid.FindBaseCell(ACol, ARow: Integer; out BaseCol, + BaseRow: Integer); +begin + if ColValid(ACol) and RowValid(ARow) then + InternalFindBaseCell(ACol, ARow, BaseCol, BaseRow); +end; + +procedure TKCustomGrid.FocusCell(ACol, ARow: Integer); +begin + if ColValid(ACol) and RowValid(ARow) then + begin + InternalFindBaseCell(ACol, ARow, ACol, ARow); + if SelectionMove(ACol, ARow, ssInit, [sfMustUpdate, sfClampInView]) then + Click; + end; +end; + +procedure TKCustomGrid.FreeData; +var + I, J: Integer; +begin + for I := 0 to FColCount - 1 do + FCols[I].Free; + FCols := nil; + for I := 0 to FRowCount - 1 do + FRows[I].Free; + FRows := nil; + for I := 0 to Length(FCells) - 1 do + for J := 0 to Length(FCells[I]) - 1 do + FCells[I, J].Free; + FCells := nil; +end; + +function TKCustomGrid.GetAllCellsSelected: Boolean; +var + R: TKGridRect; +begin + R := Selection; + NormalizeGridRect(R); + Result := (R.Col1 = FFixedCols) and (R.Col2 = FColCount - 1) and + (R.Row1 = FFixedRows) and (R.Row2 = FRowCount - 1); +end; + +function TKCustomGrid.GetAllColsSelected: Boolean; +var + R: TKGridRect; +begin + R := Selection; + NormalizeGridRect(R); + Result := (R.Row1 = FFixedRows) and (R.Row2 = FRowCount - 1); +end; + +function TKCustomGrid.GetAllRowsSelected: Boolean; +var + R: TKGridRect; +begin + R := Selection; + NormalizeGridRect(R); + Result := (R.Col1 = FFixedCols) and (R.Col2 = FColCount - 1); +end; + +procedure TKCustomGrid.GetAxisInfo(var Info: TKGridAxisInfo); +var + I, Extent: Integer; +begin + with Info do + begin + if InfoMask * [aiFixedParams, aiFullVisBoundary, aiGridBoundary, aiGridExtent] <> [] then + begin + FixedBoundary := 0; + I := 0; + while I < FixedCellCount do + begin + Inc(FixedBoundary, CellExtent(I) + EffectiveSpacing(I)); + Inc(I); + end; + end; + if aiGridExtent in InfoMask then + begin + I := FixedCellCount; + GridExtent := FixedBoundary; + while I < TotalCellCount do + begin + Inc(GridExtent, Int64(CellExtent(I)) + EffectiveSpacing(I)); + Inc(I); + end; + end; + if aiGridBoundary in InfoMask then + begin + GridCells := FirstGridCell; + GridBoundary := FixedBoundary - ScrollOffset; + while (GridCells < TotalCellCount) and (GridBoundary < ClientExtent) do + begin + Inc(GridBoundary, CellExtent(GridCells) + EffectiveSpacing(GridCells)); + Inc(GridCells); + end; + GridBoundary := Min(GridBoundary, ClientExtent); + GridCells := Min(GridCells, TotalCellCount); + end; + if aiFullVisBoundary in InfoMask then + begin + FullVisCells := FirstGridCell; + FullVisBoundary := FixedBoundary - ScrollOffset; + while FullVisCells < TotalCellCount do + begin + Extent := CellExtent(FullVisCells) + EffectiveSpacing(FullVisCells); + if FullVisBoundary + Extent <= ClientExtent then + begin + Inc(FullVisBoundary, Extent); + Inc(FullVisCells); + end else + Break; + end; + FullVisCells := Min(FullVisCells, TotalCellCount); + end; + end; +end; + +function TKCustomGrid.GetAxisInfoBoth(Mask: TKGridAxisInfoMask): TKGridAxisInfoBoth; +begin + Result.Horz := GetAxisInfoHorz(Mask); + Result.Vert := GetAxisInfoVert(Mask); +end; + +function TKCustomGrid.GetAxisInfoHorz(Mask: TKGridAxisInfoMask): TKGridAxisInfo; +begin + with Result do + begin + AlignLastCell := goAlignLastCol in FOptions; + CanResize := BeginColSizing; + CellExtent := InternalGetColWidths; + EffectiveSpacing := InternalGetEffectiveColSpacing; + FixedCellCount := FFixedCols; + FixedSelectable := gxEditFixedCols in FOptionsEx; + FirstGridCell := FTopLeft.Col; + FirstGridCellExtent := FTopLeftExtent.Col; + if HandleAllocated then + ClientExtent := ClientWidth + else + // don't create Handle, fake ClientWidth instead + ClientExtent := Width; + MinCellExtent := InternalGetMinColWidth; + MaxCellExtent := InternalGetMaxColWidth; + TotalCellCount := FColCount; + ScrollOffset := FScrollOffset.X; + InfoMask := Mask; + end; + GetAxisInfo(Result); +end; + +function TKCustomGrid.GetAxisInfoVert(Mask: TKGridAxisInfoMask): TKGridAxisInfo; +begin + with Result do + begin + AlignLastCell := goAlignLastRow in FOptions; + CanResize := BeginRowSizing; + CellExtent := InternalGetRowHeights; + EffectiveSpacing := InternalGetEffectiveRowSpacing; + FixedCellCount := FFixedRows; + FixedSelectable := gxEditFixedRows in FOptionsEx; + FirstGridCell := FTopLeft.Row; + FirstGridCellExtent := FTopLeftExtent.Row; + if HandleAllocated then + ClientExtent := ClientHeight + else + // don't create Handle, fake ClientWidth instead + ClientExtent := Height; + MinCellExtent := InternalGetMinRowHeight; + MaxCellExtent := InternalGetMaxRowHeight; + TotalCellCount := FRowCount; + ScrollOffset := FScrollOffset.Y; + InfoMask := Mask; + end; + GetAxisInfo(Result); +end; + +function TKCustomGrid.GetCell(ACol, ARow: Integer): TKGridCell; +begin + if Assigned(FCells) and ColValid(ACol) and RowValid(ARow) then + Result := InternalGetCell(ACol, ARow) + else + Result := nil; +end; + +function TKCustomGrid.GetCells(ACol, ARow: Integer): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; +var + Data: TKGridCell; +begin + Result := ''; + if Assigned(FCells) and ColValid(ACol) and RowValid(ARow) then + begin + Data := InternalGetCell(ACol, ARow); + if Data is TKGridTextCell then + Result := TKGridTextCell(Data).Text; + end; +end; + +function TKCustomGrid.GetCellSpan(ACol, ARow: Integer): TKGridCellSpan; +begin + if ColValid(ACol) and RowValid(ARow) then + Result := InternalGetCellSpan(ACol, ARow) + else + Result := MakeCellSpan(1, 1); +end; + +function TKCustomGrid.GetCols(Index: Integer): TKGridCol; +begin + if ColValid(Index) and (FCols[Index] is TKGridCol) then + Result := TKGridCol(FCols[Index]) + else + Result := nil; +end; + +function TKCustomGrid.GetColWidths(Index: Integer): Integer; +begin + if ColValid(Index) then + Result := FCols[Index].Extent + else + Result := 0 +end; + +function TKCustomGrid.GetDefaultDrawing: Boolean; +begin + Result := False; +end; + +function TKCustomGrid.GetDragRect(Info: TKGridAxisInfoBoth; out DragRect: TRect): Boolean; +var + W, H, ES: Integer; + P: TPoint; +begin + Result := False; + if FGridState = gsColMoving then + begin + if CellToPoint(FDragDest, 0, P) then + begin + if FDragDest > FDragOrigin then + begin + ES := Info.Horz.EffectiveSpacing(FDragDest); + Inc(P.X, Info.Horz.CellExtent(FDragDest)); + end else + begin + if FDragDest > 0 then + ES := Info.Horz.EffectiveSpacing(FDragDest - 1) + else + ES := 0; + Dec(P.X, ES); + end; + case FDragStyle of + dsLayeredConst, dsLayeredFaded: + begin + W := FDragArrow.Width; + H := Min(Info.Vert.FixedBoundary, Info.Vert.ClientExtent); + end; + else + W := 5; + H := Info.Vert.GridBoundary; + end; + Dec(P.X, (W - ES) shr 1); + DragRect := Rect(P.X, 0, P.X + W, H); + Result := True; + end; + end else + begin + if CellToPoint(0, FDragDest, P) then + begin + if FDragDest >= FDragOrigin then + begin + ES := Info.Vert.EffectiveSpacing(FDragDest); + Inc(P.Y, Info.Vert.CellExtent(FDragDest)); + end else + begin + if FDragDest > 0 then + ES := Info.Vert.EffectiveSpacing(FDragDest - 1) + else + ES := 0; + Dec(P.Y, ES); + end; + case FDragStyle of + dsLayeredConst, dsLayeredFaded: + begin + W := Min(Info.Horz.FixedBoundary, Info.Horz.ClientExtent); + H := FDragArrow.Height; + end; + else + W := Info.Horz.GridBoundary; + H := 5; + end; + Dec(P.Y, (H - ES) shr 1); + DragRect := Rect(0, P.Y, W, P.Y + H); + Result := True; + end; + end; +end; + +function TKCustomGrid.GetDrawState(ACol, ARow: Integer; AFocused: Boolean): TKGridDrawState; +var + BaseCol, BaseRow: Integer; +begin + Result := []; + if ColValid(ACol) and RowValid(ARow) then + begin + if (ACol < FFixedCols) or (ARow < FFixedRows) then + begin + Result := [gdFixed]; + if (goRowSorting in FOptions) and (ARow = FCols[ACol].SortArrowIndex) then + if FCols[ACol].SortMode = smDown then + Include(Result, gdRowsSortedDown) + else if FCols[ACol].SortMode = smUp then + Include(Result, gdRowsSortedUp); + if (goColSorting in FOptions) and (ACol = FRows[ARow].SortArrowIndex) and + ((ARow > 0) or not (goRowSorting in FOptions)) then + if (FRows[ARow].SortMode = smDown) then + Include(Result, gdColsSortedDown) + else if FRows[ARow].SortMode = smUp then + Include(Result, gdColsSortedUp); + //aki: + if (((gxEditFixedRows in FOptionsEx) and (ARow < FFixedRows)) or + ((gxEditFixedCols in FOptionsEx) and (ACol < FFixedCols))) and + CellSelected(ACol, ARow) then + begin + Include(Result, gdSelected); + if (ACol = FSelection.Col1) and (ARow = FSelection.Row1) then + begin + if EditorMode and (FEditor.Left >= 0) and (FEditor.Top >= 0) then + Include(Result, gdEdited) + else if AFocused then + Include(Result, gdFocused); + end; + end; + end else + begin + if CellSelected(ACol, ARow) then + begin + Result := [gdSelected]; + if (ACol = FSelection.Col1) and (ARow = FSelection.Row1) then + begin + if EditorMode and (FEditor.Left >= 0) and (FEditor.Top >= 0) then + Include(Result, gdEdited) + else if AFocused then + Include(Result, gdFocused); + end; + end else + Result := []; + if (FCols[ACol].SortMode <> smNone) or (FRows[ARow].SortMode <> smNone) then + Include(Result, gdSorted); + end; + if (FGridState in [gsNormal, gsSelecting, gsColMoveWaiting, gsRowMoveWaiting, + gsColSortWaiting, gsRowSortWaiting]) and not (csDesigning in ComponentState) then + begin + InternalFindBaseCell(ACol, ARow, BaseCol, BaseRow); + if (ACol = FMouseOver.Col) and (ARow = FMouseOver.Row) then + begin + if MouseCapture and ColValid(FHitCell.Col) and RowValid(FHitCell.Row) then + begin + InternalFindBaseCell(FHitCell.Col, FHitCell.Row, BaseCol, BaseRow); + if (BaseCol = ACol) and (BaseRow = ARow) then + Include(Result, gdMouseDown); + end; + if goMouseOverCells in FOptions then + Include(Result, gdMouseOver); + end; + end; + end; +end; + +function TKCustomGrid.GetEditorMode: Boolean; +begin + Result := Assigned(FEditor); +end; + +function TKCustomGrid.GetEffectiveColSpacing(ACol: Integer): Integer; +begin + if ColValid(ACol) then + Result := InternalGetEffectiveColSpacing(ACol) + else + Result := 0; +end; + +function TKCustomGrid.GetEffectiveRowSpacing(ARow: Integer): Integer; +begin + if RowValid(ARow) then + Result := InternalGetEffectiveRowSpacing(ARow) + else + Result := 0; +end; + +function TKCustomGrid.GetEntireColSelected(Index: Integer): Boolean; +var + R: TKGridRect; +begin + R := Selection; + NormalizeGridRect(R); + Result := (R.Row1 = FFixedRows) and (R.Row2 = FRowCount - 1) and + (R.Col1 <= Index) and (Index <= R.Col2); +end; + +function TKCustomGrid.GetEntireRowSelected(Index: Integer): Boolean; +var + R: TKGridRect; +begin + R := Selection; + NormalizeGridRect(R); + Result := (R.Col1 = FFixedCols) and (R.Col2 = FColCount - 1) and + (R.Row1 <= Index) and (Index <= R.Row2); +end; + +function TKCustomGrid.GetEntireSelectedColCount: Integer; +var + R: TKGridRect; +begin + R := Selection; + NormalizeGridRect(R); + if (R.Row1 = FFixedRows) and (R.Row2 = FRowCount - 1) then + Result := R.Col2 - R.Col1 + else + Result := 0; +end; + +function TKCustomGrid.GetEntireSelectedRowCount: Integer; +var + R: TKGridRect; +begin + R := Selection; + NormalizeGridRect(R); + if (R.Col1 = FFixedCols) and (R.Col2 = FColCount - 1) then + Result := R.Row2 - R.Row1 + else + Result := 0; +end; + +function TKCustomGrid.GetGridHeight: Integer; +begin + Result := GetAxisInfoVert([aiGridBoundary]).GridBoundary; +end; + +function TKCustomGrid.GetGridWidth: Integer; +begin + Result := GetAxisInfoHorz([aiGridBoundary]).GridBoundary; +end; + +function TKCustomGrid.GetLastVisibleCol: Integer; +begin + Result := GetAxisInfoHorz([aiGridBoundary]).GridCells - 1; +end; + +function TKCustomGrid.GetLastVisibleRow: Integer; +begin + Result := GetAxisInfoVert([aiGridBoundary]).GridCells - 1; +end; + +function TKCustomGrid.GetMoreCellsSelected: Boolean; +begin + Result := (FSelection.Row1 <> FSelection.Row2) or + (FSelection.Col1 <> FSelection.Col2); +end; + +function TKCustomGrid.GetObjects(ACol, ARow: Integer): TObject; +var + Data: TKGridCell; +begin + Result := nil; + if Assigned(FCells) and ColValid(ACol) and RowValid(ARow) then + begin + Data := InternalGetCell(ACol, ARow); + if Data is TKGridObjectCell then + Result := TKGridObjectCell(Data).CellObject; + end; +end; + +function TKCustomGrid.GetRowHeights(Index: Integer): Integer; +begin + if RowValid(Index) then + Result := FRows[Index].Extent + else + Result := 0; +end; + +function TKCustomGrid.GetRows(Index: Integer): TKGridRow; +begin + if RowValid(Index) and (FRows[Index] is TKGridRow) then + Result := TKGridRow(FRows[Index]) + else + Result := nil; +end; + +function TKCustomGrid.InternalGetSelAvail: Boolean; +begin + Result := True; +end; + +function TKCustomGrid.GetSelection: TKGridRect; +begin + Result := AdjustSelection(FSelection); +end; + +function TKCustomGrid.GetSelectionCount: Integer; +begin + Result := Length(FSelections) + 1; +end; + +function TKCustomGrid.GetSelectionRect: TRect; +begin + Result := Rect(0,0,0,0); + if GridRectToRect(Selection, Result, False, goRangeSelect in FOptions) then + begin + if FOptions * [goFixedHorzLine, goHorzLine] = [goFixedHorzLine, goHorzLine] then + Dec(Result.Bottom, GetEffectiveRowSpacing(Max(Selection.Row1, Selection.Row2))); + if FOptions * [goFixedVertLine, goVertLine] = [goFixedVertLine, goVertLine] then + Dec(Result.Right, GetEffectiveColSpacing(Max(Selection.Col1, Selection.Col2))); + end; +end; + +function TKCustomGrid.GetSelections(Index: Integer): TKGridRect; +begin + if Index = 0 then + Result := Selection + else if (Index > 0) and (Index < SelectionCount) then + Result := FSelections[Index - 1] + else + Result := GridRect(0,0,0,0); +end; + +function TKCustomGrid.GetSortCol: Integer; +var + I: Integer; +begin + Result := cInvalidIndex; + for I := 0 to FColCount - 1 do + if FCols[I].SortMode <> smNone then + begin + Result := I; + Break; + end; +end; + +function TKCustomGrid.GetSortRow: Integer; +var + I: Integer; +begin + Result := cInvalidIndex; + for I := 0 to FRowCount - 1 do + if FRows[I].SortMode <> smNone then + begin + Result := I; + Break; + end; +end; + +function TKCustomGrid.GetTabStops(Index: Integer): Boolean; +begin + if ColValid(Index) and (FCols[Index] is TKGridCol) then + Result := TKGridCol(FCols[Index]).TabStop + else + Result := True +end; + +function TKCustomGrid.GetThemedCells: Boolean; +begin + Result := Themes and (FOptions * [goThemes, goThemedCells] = [goThemes, goThemedCells]); +end; + +function TKCustomGrid.GetThemes: Boolean; +begin +{$IFDEF USE_THEMES} + Result := ThemeServices.ThemesEnabled +{$ELSE} + Result := False; +{$ENDIF} +end; + +function TKCustomGrid.GetVisibleColCount: Integer; +begin + Result := LastVisibleCol; +end; + +function TKCustomGrid.GetVisibleGridRect: TKGridRect; +begin + Result := GridRect(FTopLeft.Col, FTopLeft.Row, VisibleColCount, VisibleRowCount); +end; + +function TKCustomGrid.GetVisibleRowCount: Integer; +begin + Result := LastVisibleRow; +end; + +function TKCustomGrid.GridRectSelectable(const GridRect: TKGridRect): Boolean; +begin + Result := ColSelectable(GridRect.Col1) and ColSelectable(GridRect.Col2) and + RowSelectable(GridRect.Row1) and RowSelectable(GridRect.Row2); +end; + +function TKCustomGrid.GridRectToRect(GridRect: TKGridRect; var R: TRect; + VisibleOnly: Boolean; Merged: Boolean): Boolean; + + function Axis(const Info: TKGridAxisInfo; var Index1, Index2: Integer; Split: Boolean): Boolean; + begin + Result := True; + if Split then + begin + // adjust indexes for either fixed or nonfixed area + if Index1 >= Info.FixedCellCount then + begin + if VisibleOnly then + if Index2 >= Info.FirstGridCell then + Index1 := Max(Index1, Info.FirstGridCell) + else + Result := False; + Index2 := Max(Index2, Index1); + end else + Index2 := Min(Index2, Info.FixedCellCount - 1); + end + else if (Index1 >= Info.FixedCellCount) and VisibleOnly then + begin + if Index2 >= Info.FirstGridCell then + Index1 := Max(Index1, Info.FirstGridCell) + else + Result := False; + end; + end; + + procedure Axis1(const Info: TKGridAxisInfo; Index1, Index2, AMin: Integer; + out AMax: Integer); + var + I: Integer; + begin + AMax := AMin; + I := Index1; + if Info.CellExtent(I) = 0 then + begin + while (I >= 0) and (Info.CellExtent(I) = 0) do Dec(I); + Inc(I); + end; + while (I <= Index2) and (not VisibleOnly or (AMax < Info.ClientExtent)) do + begin + if not VisibleOnly or (I < Info.FixedCellCount) or (I >= Info.FirstGridCell) then + Inc(AMax, Info.CellExtent(I) + Info.EffectiveSpacing(I)); + // if (Index1 < Info.FirstGridCell) and (I = Info.FirstGridCell) then + // Dec(AMax, Info.ScrollOffset); + Inc(I); + end; + end; + +var + Info: TKGridAxisInfoBoth; +begin + Result := False; + NormalizeGridRect(GridRect); + if GridRectValid(GridRect) then + begin + Info := GetAxisInfoBoth([]); + if Merged then + GridRect := InternalExpandGridRect(GridRect); + // aki: + if Axis(Info.Horz, GridRect.Col1, GridRect.Col2, not (gxEditFixedCols in FOptionsEx)) and + Axis(Info.Vert, GridRect.Row1, GridRect.Row2, not (gxEditFixedRows in FOptionsEx)) then + begin + if CellToPoint(GridRect.Col1, GridRect.Row1, R.TopLeft, VisibleOnly) then + begin + Axis1(Info.Horz, GridRect.Col1, GridRect.Col2, R.Left, R.Right); + Axis1(Info.Vert, GridRect.Row1, GridRect.Row2, R.Top, R.Bottom); + Result := (R.Right > R.Left) and (R.Bottom > R.Top); + end; + end; + end; +end; + +function TKCustomGrid.GridRectValid(const GridRect: TKGridRect): Boolean; +begin + Result := ColValid(GridRect.Col1) and ColValid(GridRect.Col2) and + RowValid(GridRect.Row1) and RowValid(GridRect.Row2); +end; + +function TKCustomGrid.GridStateToInvisibleCells: TKGridInvisibleCells; +begin + case FGridState of + gsColMoving: Result := icFixedCols; + gsRowMoving: Result := icFixedRows; + gsSelecting: Result := icCells; + else + Result := icNone; + end; +end; + +function TKCustomGrid.HasFocus: Boolean; +var + Form: TCustomForm; +begin + Form := GetParentForm(Self); + if (Form <> nil) and Form.Visible and Form.Enabled and Form.Active then + Result := (Form.ActiveControl = Self) or (FEditor <> nil) and (Form.ActiveControl = FEditor) + else + Result := False; +end; + +function TKCustomGrid.HasHorzScrollBar: Boolean; +begin + Result := (FScrollBars in [ssHorizontal, ssBoth]) and + not (goAlignLastCol in FOptions); +end; + +function TKCustomGrid.HasVertScrollBar: Boolean; +begin + Result := (FScrollBars in [ssVertical, ssBoth]) and + not (goAlignLastRow in FOptions); +end; + +procedure TKCustomGrid.HideCellHint; +begin + DefaultMouseCellHint(-1, -1, False); +end; + +function TKCustomGrid.InitialCol(ACol: Integer): Integer; +var + Item: TKGridAxisItem; +begin + Item := FCols[ACol]; + if Item <> nil then + Result := Item.InitialPos + else + Result := ACol; +end; + +function TKCustomGrid.InitialColInv(ACol: Integer): Integer; +var + I: Integer; + Item: TKGridAxisItem; +begin + Result := ACol; + for I := 0 to FColCount - 1 do + begin + Item := FCols[I]; + if (Item <> nil) and (Item.InitialPos = ACol) then + begin + Result := I; + Exit; + end; + end; +end; + +function TKCustomGrid.InitialRow(ARow: Integer): Integer; +var + Item: TKGridAxisItem; +begin + Item := FRows[ARow]; + if Item <> nil then + Result := Item.InitialPos + else + Result := ARow; +end; + +function TKCustomGrid.InitialRowInv(ARow: Integer): Integer; +var + I: Integer; + Item: TKGridAxisItem; +begin + Result := ARow; + for I := 0 to FRowCount - 1 do + begin + Item := FRows[I]; + if (Item <> nil) and (Item.InitialPos = ARow) then + begin + Result := I; + Exit; + end; + end; +end; + +procedure TKCustomGrid.InsertCol(At: Integer); +begin + InsertCols(At, 1); +end; + +procedure TKCustomGrid.InsertCols(At, Count: Integer); +begin + if not ColValid(At) then At := FColCount; + ChangeDataSize(True, At, Count, False, 0, 0); +end; + +procedure TKCustomGrid.InsertRow(At: Integer); +begin + InsertRows(At, 1); +end; + +procedure TKCustomGrid.InsertRows(At, Count: Integer); +begin + if not RowValid(At) then At := FRowCount; + ChangeDataSize(False, 0, 0, True, At, Count); +end; + +function TKCustomGrid.InsertSortedCol(out ByRow, ACol: Integer): Boolean; +begin + ByRow := SortRow; + if ByRow >= 0 then + begin + ACol := InternalInsertNR(ByRow, FFixedCols, FColCount - 1, FRows[ByRow].SortMode = smUp, + CompareCols); + if ACol >= FFixedCols then + begin + LockSortMode; + try + InsertCol(ACol); + finally + UnlockSortMode; + end; + end; + end; + Result := (ByRow >= 0) and (ACol >= FFixedCols); +end; + +function TKCustomGrid.InsertSortedRow(out ByCol, ARow: Integer): Boolean; +begin + ByCol := SortCol; + if ByCol >= 0 then + begin + ARow := InternalInsertNR(ByCol, FFixedRows, FRowCount - 1, FCols[ByCol].SortMode = smUp, + CompareRows); + if ARow >= FFixedRows then + begin + LockSortMode; + try + InsertRow(ARow); + finally + UnlockSortMode; + end; + end; + end; + Result := (ByCol >= 0) and (ARow >= FFixedRows); +end; + +procedure TKCustomGrid.InternalExchangeCols(Index1, Index2: Integer); +var + I: Integer; + AxisItem: TKGridAxisItem; + CellPtr: TKGridCell; +begin + AxisItem := FCols[Index1]; + FCols[Index1] := FCols[Index2]; + FCols[Index2] := AxisItem; + if Assigned(FCells) then + begin + for I := 0 to FRowCount - 1 do + begin + CellPtr := FCells[I, Index1]; + FCells[I, Index1] := FCells[I, Index2]; + FCells[I, Index2] := CellPtr; + end; + end; + if Assigned(FOnExchangeCols) then + FOnExchangeCols(Self, Index1, Index2); + if FSelection.Col1 = Index1 then + FSelection.Col1 := Index2 + else if FSelection.Col1 = Index2 then + FSelection.Col1 := Index1; + FSelection.Col2 := FSelection.Col1; + FEditorCell.Col := FSelection.Col1; +end; + +procedure TKCustomGrid.InternalExchangeRows(Index1, Index2: Integer); +var + AxisItem: TKGridAxisItem; + CellPtr: TKGridCellRow; +begin + AxisItem := FRows[Index1]; + FRows[Index1] := FRows[Index2]; + FRows[Index2] := AxisItem; + if Assigned(FCells) then + begin + CellPtr := FCells[Index1]; + FCells[Index1] := FCells[Index2]; + FCells[Index2] := CellPtr; + end else + CellPtr := nil; + if Assigned(FOnExchangeRows) then + FOnExchangeRows(Self, Index1, Index2); + if FSelection.Row1 = Index1 then + FSelection.Row1 := Index2 + else if FSelection.Row1 = Index2 then + FSelection.Row1 := Index1; + FSelection.Row2 := FSelection.Row1; + FEditorCell.Row := FSelection.Row1; +end; + +function TKCustomGrid.InternalExpandGridRect(const GridRect: TKGridRect): TKGridRect; +var + I, J, MyCol, MyRow: Integer; + Span: TKGridCellSpan; +begin + Result := GridRect; + for I := GridRect.Col1 to GridRect.Col2 do + for J := GridRect.Row1 to GridRect.Row2 do + begin + InternalFindBaseCell(I, J, MyCol, MyRow); + Span := InternalGetCellSpan(MyCol, MyRow); + Result.Col1 := Min(Result.Col1, MyCol); + Result.Col2 := Max(Result.Col2, MyCol + Span.ColSpan - 1); + Result.Row1 := Min(Result.Row1, MyRow); + Result.Row2 := Max(Result.Row2, MyRow + Span.RowSpan - 1); + end; +end; + +procedure TKCustomGrid.InternalFindBaseCell(ACol, ARow: Integer; out BaseCol, BaseRow: Integer); +begin + BaseCol := ACol; + BaseRow := ARow; + with InternalGetCellSpan(ACol, ARow) do + if (ColSpan <= 0) and (RowSpan <= 0) then + begin + BaseCol := ACol + ColSpan; + BaseRow := ARow + RowSpan; + end; +end; + +procedure TKCustomGrid.InternalFlip(Left, Right: Integer; + Exchange: TKGridExchangeProc); +var + I: Integer; +begin + for I := 0 to (Right - Left) div 2 do + Exchange(Left + I, Right - I); +end; + +function TKCustomGrid.InternalGetCell(ACol, ARow: Integer): TKGridCell; +begin + if FCells[ARow, ACol] = nil then + FCells[ARow, ACol] := FCellClass.Create(Self); + Result := FCells[ARow, ACol]; +end; + +function TKCustomGrid.InternalGetCellSpan(ACol, ARow: Integer): TKGridCellSpan; +begin + Result := MakeCellSpan(1, 1); + if Assigned(FOnCellSpan) then + FOnCellSpan(Self, ACol, ARow, Result) + else if Assigned(FCells) then with InternalGetCell(ACol, ARow) do + Result := Span; +end; + +function TKCustomGrid.InternalGetColWidths(Index: Integer): Integer; +begin + Result := FCols[Index].Extent +end; + +function TKCustomGrid.InternalGetEffectiveColSpacing(ACol: Integer): Integer; +begin + if FCols[ACol].Extent = 0 then + begin + if (goIndicateHiddenCells in FOptions) and ((ACol = 0) or (FCols[ACol - 1].Extent <> 0)) then + Result := FHCI.VBegin.Width + else + Result := 0; + end + else if FOptions * [goFixedVertLine, goVertLine] <> [] then + begin + if (ACol = FColCount - 1) and (goAlignLastCol in FOptions) then + Result := 0 + else + Result := FGridLineWidth + end else + Result := 0; +end; + +function TKCustomGrid.InternalGetEffectiveRowSpacing(ARow: Integer): Integer; +begin + if FRows[ARow].Extent = 0 then + begin + if (goIndicateHiddenCells in FOptions) and ((ARow = 0) or (FRows[ARow - 1].Extent <> 0)) then + Result := FHCI.HBegin.Height + else + Result := 0; + end + else if FOptions * [goFixedHorzLine, goHorzLine] <> [] then + begin + if (ARow = FRowCount - 1) and (goAlignLastRow in FOptions) or + ThemedCells and (ARow < FFixedRows) and (goHeader in FOptions) then + Result := 0 + else + Result := FGridLineWidth + end else + Result := 0; +end; + +procedure TKCustomGrid.InternalGetHExtent(AIndex, AColSpan: Integer; + out DestExtent, DestSpacing: Integer); +var + I, J, K, L, Spacing: Integer; +begin + DestExtent := InternalGetColWidths(AIndex); + Spacing := InternalGetEffectiveColSpacing(AIndex); + DestSpacing := Spacing; + if AColSpan > 1 then + begin + // cell is merged across columns + if DestExtent > 0 then J := DestSpacing else J := 0; + for I := AIndex + 1 to AIndex + AColSpan - 1 do + begin + K := InternalGetColWidths(I); + L := InternalGetEffectiveColSpacing(I); + if K > 0 then + J := L; + Inc(DestExtent, K); + Inc(DestSpacing, L); + end; + if DestExtent > 0 then + begin + Inc(DestExtent, DestSpacing - J); + DestSpacing := J; + end else + DestSpacing := Spacing; + end; +end; + +procedure TKCustomGrid.InternalGetVExtent(AIndex, ARowSpan: Integer; + out DestExtent, DestSpacing: Integer); +var + I, J, K, L, Spacing: Integer; +begin + DestExtent := InternalGetRowHeights(AIndex); + Spacing := InternalGetEffectiveRowSpacing(AIndex); + DestSpacing := Spacing; + if ARowSpan > 1 then + begin + // cell is merged across rows + if DestExtent > 0 then J := DestSpacing else J := 0; + for I := AIndex + 1 to AIndex + ARowSpan - 1 do + begin + K := InternalGetRowHeights(I); + L := InternalGetEffectiveRowSpacing(I); + if K > 0 then + J := L; + Inc(DestExtent, K); + Inc(DestSpacing, L); + end; + if DestExtent > 0 then + begin + Inc(DestExtent, DestSpacing - J); + DestSpacing := J; + end else + DestSpacing := Spacing; + end; +end; + +function TKCustomGrid.InternalGetMaxColWidth(Index: Integer): Integer; +begin + if (FCols[Index].MaxExtent > 0) and not (goAlignLastCol in FOptions) then + Result := FCols[Index].MaxExtent + else + Result := MaxInt; +end; + +function TKCustomGrid.InternalGetMaxRowHeight(Index: Integer): Integer; +begin + if (FRows[Index].MaxExtent > 0) and not (goAlignLastRow in FOptions) then + Result := FRows[Index].MaxExtent + else + Result := MaxInt; +end; + +function TKCustomGrid.InternalGetMinColWidth(Index: Integer): Integer; +begin + if FCols[Index].MinExtent > 0 then + Result := FCols[Index].MinExtent + else + Result := FMinColWidth; +end; + +function TKCustomGrid.InternalGetMinRowHeight(Index: Integer): Integer; +begin + if FRows[Index].MinExtent > 0 then + Result := FRows[Index].MinExtent + else + Result := FMinRowHeight; +end; + +function TKCustomGrid.InternalGetRowHeights(Index: Integer): Integer; +begin + Result := FRows[Index].Extent; + if (Result > 0) and (Index < FFixedRows) and (goHeader in FOptions) and ThemedCells + and (FOptions * [goFixedHorzLine, goHorzLine] <> []) then + Inc(Result, FGridLineWidth); +end; + +function TKCustomGrid.InternalInsertNR(ByIndex, Left, Right: Integer; + SortedUp: Boolean; Compare: TKGridCompareProc): Integer; +var + Key, Mult: Integer; +begin + if SortedUp then Mult := -1 else Mult := 1; + repeat + Key := (Left + Right) div 2; + if Compare(ByIndex, cInvalidIndex, Key) * Mult < 0 then + Right := Key - 1 + else + Left := Key + 1; + until Left > Right; + Result := Left; +end; + +function TKCustomGrid.InternalInsertIfCellModifiedNR(ByIndex, Index, Left, Right: Integer; + SortedUp: Boolean; Compare: TKGridCompareProc): Integer; +var + Key, Mult, TmpLeft, TmpRight: Integer; +begin + Result := Index; + if SortedUp then Mult := 1 else Mult := -1; + if Left < Index then + begin + TmpLeft := Left; + TmpRight := Index - 1; + repeat + Key := (TmpLeft + TmpRight) div 2; + if Compare(ByIndex, Key, Index) * Mult < 0 then + TmpRight := Key - 1 + else + TmpLeft := Key + 1; + until TmpLeft > TmpRight; + if TmpLeft < Index then + begin + Result := TmpLeft; + Exit; + end; + end; + if Index < Right then + begin + TmpLeft := Index + 1; + TmpRight := Right; + repeat + Key := (TmpLeft + TmpRight) div 2; + if Compare(ByIndex, Key, Index) * Mult < 0 then + TmpRight := Key - 1 + else + TmpLeft := Key + 1; + until TmpLeft > TmpRight; + Result := TmpRight; + end; + Result := MinMax(Result, Left, Right); +end; + +function TKCustomGrid.InternalMove(var ACol, ARow: Integer; Command: TKGridMoveCommand; Wrap, Expanding: Boolean): Boolean; +var + BaseCol, BaseRow, BkCol, BkRow, BkBaseCol, BkBaseRow: Integer; + BkCommand: TKGridMoveCommand; +begin + BkCol := ACol; + BkRow := ARow; + BkCommand := mcNone; + InternalFindBaseCell(ACol, ARow, BkBaseCol, BkBaseRow); + repeat + case Command of + mcDown: + begin + Inc(ARow); + if ARow < FRowCount then + begin + if FMemCol >= 0 then + ACol := FMemCol; + FMemRow := ARow; + end + else if Wrap then + begin + ARow := FFixedRows; + Inc(ACol); + if ACol >= FColCount then + begin + // aki: + if (gxEditFixedCols in FOptionsEx) or ((gxEditFixedRows in FOptionsEx) and (ARow < FFixedRows)) then + ACol := 0 + else + ACol := FFixedCols; + end; + FMemCol := ACol; + end + else if BkCommand <> mcNone then + begin + Dec(ARow); + Command := BkCommand; + BkCommand := mcNone; + end else + ARow := BkRow; + end; + mcEnd: + begin + ACol := FColCount - 1; + FMemCol := ACol; + if FMemRow >= 0 then + ARow := FMemRow; + Command := mcLeft; + end; + mcHome: + begin + // aki: + if (gxEditFixedCols in FOptionsEx) or ((gxEditFixedRows in FOptionsEx) and (ARow < FFixedRows)) then + ACol := 0 + else + ACol := FFixedCols; + FMemCol := ACol; + if FMemRow >= 0 then + ARow := FMemRow; + Command := mcRight; + end; + mcLeft: + begin + Dec(ACol); + // aki: + if (gxEditFixedCols in FOptionsEx) or ((gxEditFixedRows in FOptionsEx) and (ARow= 0 then + begin + if FMemRow >= 0 then + ARow := FMemRow; + FMemCol := ACol; + end + else + if Wrap then + begin + ACol := FColCount - 1; + Dec(ARow); + if ARow < 0 then ARow := FRowCount - 1; + FMemRow := ARow; + end + else if BkCommand <> mcNone then + begin + Inc(ACol); + Command := BkCommand; + BkCommand := mcNone; + end else + ACol := BkCol; + end else + begin + if ACol >= FFixedCols then + begin + if FMemRow >= 0 then + ARow := FMemRow; + FMemCol := ACol; + end + else if Wrap then + begin + ACol := FColCount - 1; + Dec(ARow); + if ARow < FFixedRows then ARow := FRowCount - 1; + FMemRow := ARow; + end + else if BkCommand <> mcNone then + begin + Inc(ACol); + Command := BkCommand; + BkCommand := mcNone; + end else + ACol := BkCol; + end; + end; + mcMoveUp: + begin + // aki: + if ((gxEditFixedRows in FOptionsEx) or (ARow > FFixedRows)) and (FMemCol >= 0) then + ACol := FMemCol; + ARow := FTopLeft.Row; + Command := mcUp; + BkCommand := mcDown; + end; + mcMoveDown: + begin + if (ARow < FRowCount - 1) and (FMemCol >= 0) then + ACol := FMemCol; + ARow := FTopLeft.Row + PageHeight - 1; + Command := mcDown; + BkCommand := mcUp; + end; + mcRight: + begin + Inc(ACol); + if ACol < FColCount then + begin + if FMemRow >= 0 then + ARow := FMemRow; + FMemCol := ACol; + end + else if Wrap then + begin + ACol := FFixedCols; + Inc(ARow); + if ARow >= FRowCount then ARow := FFixedRows; + FMemRow := ARow; + end + else if BkCommand <> mcNone then + begin + Dec(ACol); + Command := BkCommand; + BkCommand := mcNone; + end else + ACol := BkCol; + end; + mcUp: + begin + Dec(ARow); + // aki: + if (ARow >= FFixedRows) or ((gxEditFixedRows in FOptionsEx) and (ARow >= 0)) then + begin + if FMemCol >= 0 then + ACol := FMemCol; + FMemRow := ARow; + end + else if Wrap then + begin + ARow := FRowCount - 1; + Dec(ACol); + if ACol < FFixedCols then ACol := FColCount - 1; + FMemCol := ACol; + end + else if BkCommand <> mcNone then + begin + Inc(ARow); + Command := BkCommand; + BkCommand := mcNone; + end else + ARow := BkRow; + end; + mcPageDown: + begin + if (ARow < FRowCount - 1) and (FMemCol >= 0) then + ACol := FMemCol; + ARow := Min(ARow + PageHeight, FRowCount - 1); + Command := mcDown; + BkCommand := mcUp; + FMemRow := ARow; + end; + mcPageLeft: + begin + if (ARow > FFixedCols) and (FMemRow >= 0) then + ARow := FMemRow; + ACol := Max(ACol - PageWidth, FFixedCols); + Command := mcLeft; + BkCommand := mcRight; + FMemCol := ACol; + end; + mcPageRight: + begin + if (ARow < FColCount - 1) and (FMemRow >= 0) then + ARow := FMemRow; + ACol := Min(ACol + PageWidth, FColCount - 1); + Command := mcRight; + BkCommand := mcLeft; + FMemCol := ACol; + end; + mcPageUp: + begin + if (ARow > FFixedRows) and (FMemCol >= 0) then + ACol := FMemCol; + ARow := Max(ARow - PageHeight, FFixedRows); + Command := mcUp; + BkCommand := mcDown; + FMemRow := ARow; + end; + mcTop: + begin + ACol := FFixedCols; + ARow := FFixedRows; + FMemCol := ACol; + FMemRow := ARow; + Command := mcRight; + Wrap := True; + end; + mcBottom: + begin + ACol := FColCount - 1; + ARow := FRowCount - 1; + FMemCol := ACol; + FMemRow := ARow; + Command := mcLeft; + Wrap := True; + end; + end; + InternalFindBaseCell(ACol, ARow, BaseCol, BaseRow); + until (ACol = BkCol) and (ARow = BkRow) or ((BaseCol <> BkBaseCol) or (BaseRow <> BkBaseRow)) and + (not Expanding and SelectCell(BaseCol, BaseRow) or Expanding and SelectionExpand(BaseCol, BaseRow)); + Result := (ACol <> BkCol) or (ARow <> BkRow); + ACol := BaseCol; + ARow := BaseRow; +end; + +procedure TKCustomGrid.InternalPaintCell(ACol, ARow: Integer; AState: TKGridDrawState; + const ARect, ABlockRect: TRect; ACanvas: TCanvas; Clip, Printing: Boolean); +begin + FCellPainter.Col := ACol; + FCellPainter.Row := ARow; + FCellPainter.State := AState; + FCellPainter.CellPos := ARect.TopLeft; + FCellPainter.Canvas := ACanvas; + FCellPainter.CellRect := ARect; + FCellPainter.BlockRect := ABlockRect; + FCellPainter.FPrinting := Printing; + // prepare cell painter and draw cell + FCellPainter.BeginDraw; + try + if Clip or Printing then + FCellPainter.BeginClip; + try +// FCellPainter.Canvas.TextRect(ARect, ARect.Left, ARect.Top, 'debugtest'); + if not DrawCell(FCellPainter.Col, FCellPainter.Row, FCellPainter.CellRect, FCellPainter.State) then + FCellPainter.DrawEmptyCell; // stub function + finally + FCellPainter.EndClip; + end; + finally + FCellPainter.EndDraw; + end; +end; + +procedure TKCustomGrid.InternalQuickSortNR(ByIndex, Left, Right: Integer; + SortedDown: Boolean; Compare: TKGridCompareProc; Exchange: TKGridExchangeProc); +type + TStackItem = record + LIndex, RIndex: Integer; + end; +const + cStackGrow = 100; +var + Key, L, R, LBack, RBack, StackLen, StackPtr: Integer; + Stack: array of TStackItem; +begin + { this is the non recursive quick sort algorithm to avoid stack overflows. + Right parts of divided arrays are stored into a stack-like array + in dynamic memory for later use. } + SetLength(Stack, cStackGrow); + StackPtr := 0; + with Stack[StackPtr] do begin LIndex := Left; RIndex := Right end; + repeat + with Stack[StackPtr] do begin Left := LIndex; Right := RIndex end; + Dec(StackPtr); + repeat + L := Left; + R := Right; + Key := (L + R) div 2; + LBack := Left - 1; + RBack := Right; + repeat + if SortedDown then + begin + while (L < Right) and (Compare(ByIndex, L, Key) < 0) do Inc(L); + while (R > Left) and (Compare(ByIndex, R, Key) > 0) do Dec(R); + end else + begin + while (L < Right) and (Compare(ByIndex, L, Key) > 0) do Inc(L); + while (R > Left) and (Compare(ByIndex, R, Key) < 0) do Dec(R); + end; + if L <= R then + begin + if L < R then + if (L = Key) or (R = Key) then + begin + // preserve Key, exchange later + LBack := L; + RBack := R; + end else + Exchange(L, R); + Dec(R); + Inc(L); + end; + until L >= R; + // exchange anything with former Key + if LBack >= Left then + Exchange(LBack, RBack); + if L < Right then + begin + Inc(StackPtr); + StackLen := Length(Stack); + if StackPtr >= StackLen then + SetLength(Stack, StackLen + cStackGrow); + with Stack[StackPtr] do begin LIndex := L; RIndex := Right end; + end; + Right := R; + until Left >= Right; + until StackPtr < 0; +end; + +procedure TKCustomGrid.InternalSetCell(ACol, ARow: Integer; Value: TKGridCell); +var + TmpClass: TClass; + TmpCell: TKGridCell; + Span: TKGridCellSpan; +begin + if FCells[ARow, ACol] <> nil then + Span := FCells[ARow, ACol].Span + else + Span := MakeCellSpan(1, 1); + FreeAndNil(FCells[ARow, ACol]); + if Value <> nil then + begin + TmpClass := Value.ClassType; + TmpCell := TKGridCellClass(TmpClass).Create(Self); + FlagSet(cGF_GridUpdates); + try + TmpCell.Assign(Value); + TmpCell.Span := Span; + finally + FlagClear(cGF_GridUpdates); + end; + FCells[ARow, ACol] := TmpCell; + end; + InvalidateCell(ACol, ARow); +end; + +procedure TKCustomGrid.InternalSetCells(ACol, ARow: Integer; const Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); +var + Cell, Tmp: TKGridCell; +begin + Cell := InternalGetCell(ACol, ARow); + FlagSet(cGF_GridUpdates); + try + if not (Cell is TKGridTextCell) then + begin + if FCellClass.InheritsFrom(TKGridTextCell) then + Tmp := FCellClass.Create(Self) + else + Tmp := TKGridTextCell.Create(Self); + Tmp.Assign(Cell); + Cell.Free; + FCells[ARow, ACol] := Tmp; + end; + TKGridTextCell(FCells[ARow, ACol]).Text := Text; + finally + FlagClear(cGF_GridUpdates); + end; + InvalidateCell(ACol, ARow); +end; + +function TKCustomGrid.InternalSetCellSpan(ACol, ARow: Integer; + const Value: TKGridCellSpan): TKGridRect; + + procedure Merge(ACol1, ARow1, ACol2, ARow2: Integer); + var + I, J: Integer; + Cell: TKGridCell; + begin + for I := ACol1 to ACol2 - 1 do + for J := ARow1 to ARow2 - 1 do + begin + Cell := InternalGetCell(I, J); + if (I = ACol1) and (J = ARow1) then + Cell.Span := MakeCellSpan(ACol2 - ACol1, ARow2 - ARow1) + else + Cell.Span := MakeCellSpan(ACol1 - I, ARow1 - J); + end; + end; + + procedure Split(ACol1, ARow1, ACol2, ARow2: Integer); + var + I, J: Integer; + RefSpan: TKGridCellSpan; + begin + RefSpan := MakeCellSpan(1, 1); + for I := ACol1 to ACol2 - 1 do + for J := ARow1 to ARow2 - 1 do + InternalGetCell(I, J).Span := RefSpan; + end; + +var + I, J, BaseCol, BaseRow: Integer; + Span: TKGridCellSpan; + Cell: TKGridCell; +begin + Result := GridRect(ACol, ARow, ACol + Value.ColSpan - 1, ARow + Value.ColSpan - 1); + if (ACol >= FFixedCols) and (ARow >= FFixedRows) then + FlagSet(cGF_SelCellsMerged); + Span := InternalGetCell(ACol, ARow).Span; + if (Span.ColSpan > 1) or (Span.RowSpan > 1) then + begin + // destroy previously merged area + Split(ACol, ARow, ACol + Span.ColSpan, ARow + Span.RowSpan); + Result.Col2 := Max(Result.Col2, ACol + Span.ColSpan - 1); + Result.Row2 := Max(Result.Row2, ARow + Span.RowSpan - 1); + end; + for I := ACol to ACol + Value.ColSpan - 1 do + for J := ARow to ARow + Value.RowSpan - 1 do + begin + Cell := InternalGetCell(I, J); + Span := Cell.Span; + if (Span.ColSpan <> 1) or (Span.RowSpan <> 1) then + begin + // adjust all four overlapping spans + InternalFindBaseCell(I, J, BaseCol, BaseRow); + if (BaseCol <> ACol) or (BaseRow <> ARow) then + begin + Span := InternalGetCell(BaseCol, BaseRow).Span; + Split(Max(ACol, BaseCol), Max(ARow, BaseRow), + Min(ACol + Value.ColSpan, BaseCol + Span.ColSpan), Min(ARow + Value.RowSpan, BaseRow + Span.RowSpan)); + Merge(BaseCol, BaseRow, BaseCol + Span.ColSpan, ARow); + Merge(BaseCol, ARow + Value.RowSpan, BaseCol + Span.ColSpan, BaseRow + Span.RowSpan); + Merge(BaseCol, Max(ARow, BaseRow), ACol, Min(ARow + Value.RowSpan, BaseRow + Span.RowSpan)); + Merge(ACol + Value.ColSpan, Max(ARow, BaseRow), BaseCol + Span.ColSpan, Min(ARow + Value.RowSpan, BaseRow + Span.RowSpan)); + Result.Col1 := Min(Result.Col1, BaseCol); + Result.Row1 := Min(Result.Row1, BaseRow); + Result.Col2 := Max(Result.Col2, BaseCol + Span.ColSpan - 1); + Result.Row2 := Max(Result.Row2, BaseRow + Span.RowSpan - 1); + end; + end; + if (I = ACol) and (J = ARow) then + Cell.Span := Value + else + Cell.Span := MakeCellSpan(ACol - I, ARow - J); + end; +end; + +procedure TKCustomGrid.InternalSetColCount(Value: Integer); +begin + if Value > FColCount then + ChangeDataSize(True, FColCount, Value - FColCount, False, 0, 0) + else if Value < FColCount then + ChangeDataSize(False, Value, FColCount - Value, False, 0, 0); +end; + +procedure TKCustomGrid.InternalSetFixedCols(Value: Integer); +begin + ColCount := Max(ColCount, Value + 1); + FFixedCols := Value; + ResetTopLeft; + SelectionFix(FSelection); + UpdateAxes(True, cAll, False, cAll, []); +end; + +procedure TKCustomGrid.InternalSetFixedRows(Value: Integer); +begin + RowCount := Max(RowCount, Value + 1); + FFixedRows := Value; + ResetTopLeft; + SelectionFix(FSelection); + UpdateAxes(False, cAll, True, cAll, []); +end; + +procedure TKCustomGrid.InternalSetRowCount(Value: Integer); +begin + if Value > FRowCount then + ChangeDataSize(False, 0, 0, True, FRowCount, Value - FRowCount) + else if Value < FRowCount then + ChangeDataSize(False, 0, 0, False, Value, FRowCount - Value); +end; + +function TKCustomGrid.InternalUpdateVirtualGrid: Boolean; +begin + Result := True; +end; + +procedure TKCustomGrid.InternalUnlockUpdate; +begin + ClearSortMode; + UpdateAxes(True, cAll, True, cAll, [afCheckMinExtent]); +end; + +procedure TKCustomGrid.InvalidateCell(ACol, ARow: Integer); +begin + InvalidateGridRect(GridRect(GridPoint(ACol, ARow))); +end; + +procedure TKCustomGrid.InvalidateCol(ACol: Integer); +var + GR: TKGridRect; +begin + if UpdateUnlocked and HandleAllocated then + begin + ACol := MinMax(ACol, 0, FColCount - 1); + GR.Col1 := ACol; + GR.Col2 := ACol; + if FFixedRows > 0 then + begin + GR.Row1 := 0; + GR.Row2 := FFixedRows - 1; + InvalidateGridRect(GR); + end; + GR.Row1 := FFixedRows; + GR.Row2 := LastVisibleRow; + InvalidateGridRect(GR); + end; +end; + +procedure TKCustomGrid.InvalidateCols(FirstCol: Integer); +var + Boundary, FirstRow: Integer; + P: TPoint; + R: TRect; + GR: TKGridRect; +begin + if UpdateUnlocked and HandleAllocated then + begin + FirstCol := MinMax(FirstCol, 0, FColCount - 1); + if FirstCol >= FFixedCols then + FirstCol := Max(FirstCol, FTopLeft.Col); + if FFixedRows > 0 then + begin + GR := GridRect(FirstCol, 0, FirstCol, FFixedRows - 1); + GR := InternalExpandGridRect(GR); + Boundary := GR.Col1; + FirstRow := 0; + end else + begin + Boundary := MaxInt; + FirstRow := FTopLeft.Row; + end; + GR := GridRect(FirstCol, FTopLeft.Row, FirstCol, LastVisibleRow); + GR := InternalExpandGridRect(GR); + FirstCol := Min(Boundary, GR.Col1); + if FirstCol >= FFixedCols then + FirstCol := Max(FirstCol, FTopLeft.Col); + if CellToPoint(FirstCol, FirstRow, P, True) then + begin + if FirstCol >= FFixedCols then + Boundary := GetAxisInfoHorz([aiFixedParams]).FixedBoundary + else + Boundary := 0; + R := Rect(Max(P.X, Boundary), 0, ClientWidth, ClientHeight); + InvalidateRect(Handle, @R, False); + end; + end; +end; + +procedure TKCustomGrid.InvalidateCurrentSelection; +begin + InvalidateSelection(Selection); + if EditorMode and CellInGridRect(Col, Row, Selection) then + FEditor.Invalidate; +end; + +procedure TKCustomGrid.InvalidateGridRect(const GR: TKGridRect; Merged: Boolean); +var + R: TRect; +begin + if UpdateUnlocked and HandleAllocated and GridRectToRect(GR, R, True, Merged) then + InvalidateRect(Handle, @R, False); +end; + +procedure TKCustomGrid.InvalidateRow(ARow: Integer); +var + GR: TKGridRect; +begin + if UpdateUnlocked and HandleAllocated then + begin + ARow := MinMax(ARow, 0, FRowCount - 1); + GR.Row1 := ARow; + GR.Row2 := ARow; + if FFixedCols > 0 then + begin + GR.Col1 := 0; + GR.Col2 := FFixedCols - 1; + InvalidateGridRect(GR); + end; + GR.Col1 := FFixedCols; + GR.Col2 := LastVisibleCol; + InvalidateGridRect(GR); + end; +end; + +procedure TKCustomGrid.InvalidateRows(FirstRow: Integer); +var + Boundary, FirstCol: Integer; + P: TPoint; + R: TRect; + GR: TKGridRect; +begin + if UpdateUnlocked and HandleAllocated then + begin + FirstRow := MinMax(FirstRow, 0, FRowCount - 1); + if FirstRow >= FFixedRows then + FirstRow := Max(FirstRow, FTopLeft.Row); + if FFixedCols > 0 then + begin + GR := GridRect(0, FirstRow, FFixedCols - 1, FirstRow); + GR := InternalExpandGridRect(GR); + Boundary := GR.Row1; + FirstCol := 0; + end else + begin + Boundary := MaxInt; + FirstCol := FTopLeft.Col; + end; + GR := GridRect(FirstCol, FirstRow, LastVisibleCol, FirstRow); + GR := InternalExpandGridRect(GR); + FirstRow := Min(Boundary, GR.Row1); + if FirstRow >= FFixedRows then + FirstRow := Max(FirstRow, FTopLeft.Row); + if CellToPoint(FirstCol, FirstRow, P, True) then + begin + if FirstRow >= FFixedRows then + Boundary := GetAxisInfoVert([aiFixedParams]).FixedBoundary + else + Boundary := 0; + R := Rect(0, Max(P.Y, Boundary), ClientWidth, ClientHeight); + InvalidateRect(Handle, @R, False); + end; + end; +end; + +procedure TKCustomGrid.InvalidateSelection(ASelection: TKGridRect); +var + R: TRect; +begin + if UpdateUnlocked and HandleAllocated then + begin + ASelection := AdjustSelection(ASelection); + if GridRectToRect(ASelection, R, True) then + InvalidateRect(Handle, @R, False); + if goIndicateSelection in FOptions then + begin + // this causes extremely slow painting under GTKx! + // do not use goIndicateSelection here! + if not (goRowSelect in FOptions) and (FFixedRows > 0) and GridRectToRect( + GridRect(ASelection.Col1, 0, ASelection.Col2, FFixedRows - 1), R, True) then + InvalidateRect(Handle, @R, False); + if (FFixedCols > 0) and GridRectToRect( + GridRect(0, ASelection.Row1, FFixedCols - 1, ASelection.Row2), R, True) then + InvalidateRect(Handle, @R, False); + end; + end; +end; + +function TKCustomGrid.IsDoubleBuffered: Boolean; +begin + Result := DoubleBuffered or (goDoubleBufferedCells in FOptions); +end; + +function TKCustomGrid.IsThemed: Boolean; +begin + Result := goThemes in FOptions; +end; + +procedure TKCustomGrid.KeyDown(var Key: Word; Shift: TShiftState); +var + ACol, ARow, ATopRow, SelCol, SelRow: Integer; + Stage: TKGridSelectionStage; + Expanding: Boolean; +begin + inherited; + SelCol := FSelection.Col1; + SelRow := FSelection.Row1; + Expanding := False; + if ssShift in Shift then + begin + Stage := ssExpand; + if (goRangeSelect in FOptions) and (FRangeSelectStyle = rsMS_Excel) then + begin + SelCol := FSelection.Col2; + SelRow := FSelection.Row2; + Expanding := True; + end; + end else + Stage := ssInit; + ACol := SelCol; + ARow := SelRow; + ATopRow := FTopLeft.Row; + if ssCtrl in Shift then + case Key of + VK_UP: Dec(ATopRow); + VK_DOWN: Inc(ATopRow); + VK_LEFT: InternalMove(ACol, ARow, mcPageLeft, False, Expanding); + VK_RIGHT: InternalMove(ACol, ARow, mcPageRight, False, Expanding); + VK_PRIOR: InternalMove(Acol, ARow, mcMoveUp, False, Expanding); + VK_NEXT: InternalMove(Acol, ARow, mcMoveDown, False, Expanding); + VK_HOME: InternalMove(Acol, ARow, mcTop, False, Expanding); + VK_END: InternalMove(Acol, ARow, mcBottom, False, Expanding); + end + else + case Key of + VK_RETURN: + begin + FlagSet(cGF_EnterPressed); + if goEnterMoves in FOptions then + begin + if (ACol = FColCount - 1) and (ARow = FRowCount - 1) and (gxEnterAppendsRow in FOptionsEx) then + begin + InsertRow(FRowCount); + InternalMove(ACol, ARow, DirectionToCommand(FMoveDirection), True, Expanding); + end else + InternalMove(ACol, ARow, DirectionToCommand(FMoveDirection), (gxEnterWraps in FOptionsEx), Expanding); + end else + EditorMode := not EditorMode; + end; + VK_ESCAPE: + begin + CancelMode; + if EditorMode then + begin + EditorDataFromGrid(FEditor, FEditorCell.Col, FEditorCell.Row); + EditorMode := False; + end; + end; + VK_UP: InternalMove(ACol, ARow, mcUp, False, Expanding); + VK_DOWN: InternalMove(ACol, ARow, mcDown, False, Expanding); + VK_LEFT: InternalMove(ACol, ARow, mcLeft, False, Expanding); + VK_RIGHT: InternalMove(ACol, ARow, mcRight, False, Expanding); + VK_NEXT: InternalMove(ACol, ARow, mcPageDown, False, Expanding); + VK_PRIOR: InternalMove(ACol, ARow, mcPageUp, False, Expanding); + VK_HOME: InternalMove(ACol, ARow, mcHome, False, Expanding); + VK_END: InternalMove(ACol, ARow, mcEnd, False, Expanding); + VK_TAB: + begin + if goTabs in FOptions then + begin + if not (ssAlt in Shift) then + repeat + if ssShift in Shift then + begin + InternalMove(ACol, ARow, mcLeft, gxTabWraps in FOptionsEx, Expanding); + Stage := ssInit; + end else + begin + if (ACol = FColCount - 1) and (ARow = FRowCount - 1) and (gxTabAppendsRow in FOptionsEx) then + begin + InsertRow(FRowCount); + InternalMove(ACol, ARow, mcRight, True, Expanding); + end else + InternalMove(ACol, ARow, mcRight, gxTabWraps in FOptionsEx, Expanding); + end; + until TabStops[ACol] or (ACol = FSelection.Col1); + end; + end; + VK_F2: EditorMode := True; + end; + DefaultSetCaretToLeft(Key, Shift); + // aki: + if (gxEditFixedCols in FOptionsEx) and (gxEditFixedRows in FOptionsEx) then + begin + ACol := MinMax(ACol, 0, FColCount - 1); + ARow := MinMax(ARow, 0, FRowCount - 1); + end + else if (gxEditFixedCols in FOptionsEx) then + begin + ACol := MinMax(ACol, 0, FColCount - 1); + ARow := MinMax(ARow, FFixedRows, FRowCount - 1); + end + else if (gxEditFixedRows in FOptionsEx) and (ARow < FFixedRows) then + begin + ACol := MinMax(ACol, 0, FColCount - 1); + ARow := MinMax(ARow, 0, FRowCount - 1); + end else + begin + ACol := MinMax(ACol, FFixedCols, FColCount - 1); + ARow := MinMax(ARow, FFixedRows, FRowCount - 1); + end; + if (ACol <> SelCol) or (ARow <> SelRow) then + begin + if SelectionMove(ACol, ARow, Stage, [sfMustUpdate, sfClampInView, sfDontCallSelectCell, sfNoMemPos]) then + begin + Click; + if not (goAlwaysShowEditor in FOptions) then + EditorMode := False; + Key := 0; + end; + end + else if ATopRow <> FTopLeft.Row then + TopRow := MinMax(ATopRow, FFixedRows, FRowCount - 1); + // whenever set, this flag is only valid for the nearest KeyDown call + FlagClear(cGF_CaretToLeft or cGF_EnterPressed); +end; + +procedure TKCustomGrid.Loaded; +begin + inherited; + FColors.ClearBrightColors; + FColors.BrightRangeBkGnds; +end; + +procedure TKCustomGrid.LateUpdate(var Msg: TLMessage); +begin + inherited; + case Msg.Msg of + CN_KEYDOWN: + begin + KeyDown(TLMKey(Msg).CharCode, KeyDataToShiftState(TLMKey(Msg).KeyData)); + end; + LM_SETFOCUS: + begin + InvalidateCurrentSelection; + SafeSetFocus; + end; + end; +end; + +procedure TKCustomGrid.LockSortMode; +begin + Inc(FSortModeLock); +end; + +function TKCustomGrid.MeasureCell(ACol, ARow: Integer; const ARect: TRect; + AState: TKGridDrawState; Priority: TKGridMeasureCellPriority): TPoint; +begin + FCellPainter.Col := ACol; + FCellPainter.Row := ARow; + FCellPainter.State := AState; + FCellPainter.CellPos := ARect.TopLeft; + FCellPainter.Canvas := Canvas; + FCellPainter.CellRect := ARect; + FCellPainter.FPrinting := False; + // prepare cell painter and measure cell data + FCellPainter.BeginDraw; + try + Result.X := ARect.Right - ARect.Left; + Result.Y := ARect.Bottom - ARect.Top; + if Assigned(FOnMeasureCell) then + FOnMeasureCell(Self, ACol, ARow, ARect, AState, Priority, Result) + else if Assigned(FCells) then with InternalGetCell(ACol, ARow) do + begin + ApplyDrawProperties; + MeasureCell(ACol, ARow, ARect, AState, Priority, Result) + end else + Result := FCellPainter.DefaultMeasure(Priority); + finally + FCellPainter.EndDraw; + end; +end; + + +procedure TKCustomGrid.MeasurePages(var Info: TKPrintMeasureInfo); + + procedure Axis(const Info: TKGridAxisInfo; CanvasExtent, SelStart, SelEnd: Integer; + SelOnly, FitToPage: Boolean; out Pages, OutlineExtent: Integer); + var + I, StartIndex, EndIndex, Extent, PageExtent: Integer; + begin + Pages := 1; + PageExtent := 0; + OutlineExtent := 0; + if SelOnly then + begin + StartIndex := SelStart; + EndIndex := SelEnd; + end else + begin + StartIndex := 0; + EndIndex := Info.TotalCellCount - 1; + end; + for I := StartIndex to EndIndex do + begin + Extent := Info.CellExtent(I) + Info.EffectiveSpacing(I); + if FitToPage or (PageExtent + Extent < CanvasExtent) or (I = 0) then + Inc(PageExtent, Extent) + else + begin + Inc(Pages); + OutlineExtent := Max(OutlineExtent, PageExtent); + PageExtent := Extent; + end; + end; + OutlineExtent := Max(OutlineExtent, PageExtent); + end; + +var + ColPages, RowPages: Integer; + Scale: Double; + FitToPage, SelOnly: Boolean; + R: TKGridRect; + APageSetup: TKPrintPageSetup; +begin + R := InternalExpandGridRect(Selection); + NormalizeGridRect(R); + APageSetup := PageSetup; + FitToPage := poFitToPage in APageSetup.Options; + SelOnly := APageSetup.Range = prSelectedOnly; + Scale := APageSetup.Scale / 100; + Axis(GetAxisInfoHorz([]), Round(APageSetup.PaintAreaWidth / Scale), R.Col1, R.Col2, + SelOnly, FitToPage, ColPages, Info.OutlineWidth); + if FitToPage then + Scale := APageSetup.PaintAreaWidth / Info.OutlineWidth; + Axis(GetAxisInfoVert([]), Round(APageSetup.PaintAreaHeight / Scale), R.Row1, R.Row2, + SelOnly, False, RowPages, Info.OutlineHeight); + Info.HorzPageCount := ColPages; + Info.VertPageCount := RowPages; + Info.PageCount := ColPages * RowPages; +end; + +procedure TKCustomGrid.MouseCellHint(ACol, ARow: Integer; AShow: Boolean); +begin + if Assigned(FOnMouseCellHint) then + FOnMouseCellHint(Self, ACol, ARow, AShow) + else + DefaultMouseCellHint(ACol, ARow, AShow); +end; + +procedure TKCustomGrid.MouseClickCell(ACol, ARow: Integer); +begin + if (gxFixedCellClickSelect in FOptionsEx) and ((ARow < FFixedRows) or (ACol < FFixedCols)) and (ssShift in GetShiftState) then + begin + if (ARow < FFixedRows) and (ACol < FFixedCols) then + begin + if AllCellsSelected then + UnselectRange + else + SelectAll; + end else + begin + if ACol >= FFixedCols then + begin + if EntireColSelected[ACol] then + UnselectRange + else + SelectCol(ACol); + end else + begin + if EntireRowSelected[ARow] then + UnselectRange + else + SelectRow(ARow); + end; + end; + end; + if Assigned(FOnMouseClickCell) then + FOnMouseClickCell(Self, ACol, ARow); +end; + +procedure TKCustomGrid.MouseDblClickCell(ACol, ARow: Integer); +begin + if Assigned(FOnMouseDblClickCell) then + FOnMouseDblClickCell(Self, ACol, ARow); +end; + +procedure TKCustomGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; + X, Y: Integer); +var + BaseCol, BaseRow: Integer; + CellFound: Boolean; + State: TKGridState; +begin + inherited; + if (Button = mbLeft) and not FScrollTimer.Enabled then + begin + SafeSetFocus; + if ssDouble in Shift then + DblClick; + FHitPos := Point(X, Y); + State := gsNormal; + CellFound := PointToCell(FHitPos, False, icNone, FHitCell.Col, FHitCell.Row, BaseCol, BaseRow); + if CellFound then + InternalFindBaseCell(FHitCell.Col, FHitCell.Row, BaseCol, BaseRow); + if PointToSizing(FHitPos, State, FSizingIndex, FSizingDest) then + begin + if (State = gsColSizing) and + BeginColSizing(FSizingIndex, FSizingDest) or + (State = gsRowSizing) and + BeginRowSizing(FSizingIndex, FSizingDest) then + begin + FGridState := State; + if CellFound then + InvalidateCell(BaseCol, BaseRow); + Update; + SuggestSizing(csStart); + end; + end + else if CellFound then + begin + if FMouseOver.Col >= 0 then + begin + MouseCellHint(FMouseOver.Col, FMouseOver.Row, False); + FCellHintTimer.Enabled := False; + end; + // aki: row for greater than fixed cols: + if (FHitCell.Row < FFixedRows) and (FHitCell.Col >= FFixedCols) and (not (gxEditFixedRows in FOptionsEx)) then + begin + if goColMoving in FOptions then + FGridState := gsColMoveWaiting + else if goRowSorting in FOptions then + FGridState := gsRowSortWaiting; + end + // aki: col + else if ((FHitCell.Col < FFixedCols) and (FHitCell.Row >= FFixedRows)) and (not (gxEditFixedCols in FOptionsEx)) then + begin + if goRowMoving in FOptions then + FGridState := gsRowMoveWaiting + else if goColSorting in FOptions then + FGridState := gsColSortWaiting; + end + // aki: row for greater than fixed row: + else if ((FHitCell.Col < FFixedCols) and (FHitCell.Row < FFixedRows)) and (not (gxEditFixedRows in FOptionsEx)) then + begin + FGridState := gsClickWaiting; + end else + begin + FlagSet(cGF_SelectedByMouse); + try + if SelectionMove(BaseCol, BaseRow, ssInit, [sfMustUpdate, sfClampInView]) then + begin + FGridState := gsSelecting; + EditorMode := (goAlwaysShowEditor in FOptions) or (ssDouble in Shift); + end; + finally + FlagClear(cGF_SelectedByMouse); + end; + end; + InvalidateCell(BaseCol, BaseRow); + if ssDouble in Shift then + MouseDblClickCell(BaseCol, BaseRow); + end; + end; +end; + +procedure TKCustomGrid.MouseEnterCell(ACol, ARow: Integer); +begin + if Assigned(FOnMouseEnterCell) then + FOnMouseEnterCell(Self, ACol, ARow); +end; + +procedure TKCustomGrid.MouseFormLeave; +var + P: TPoint; +begin + inherited; + if EditorMode then + begin + P := FEditor.ScreenToClient(Mouse.CursorPos); + if PtInRect(FEditor.ClientRect, P) then + FEditor.Perform(CM_MOUSEENTER, 0, 0) + else + MouseOverCells; + end else + MouseOverCells; +end; + +procedure TKCustomGrid.MouseLeaveCell(ACol, ARow: Integer); +begin + if Assigned(FOnMouseLeaveCell) then + FOnMouseLeaveCell(Self, ACol, ARow); +end; + +procedure TKCustomGrid.MouseMove(Shift: TShiftState; X, Y: Integer); + + function CanDrag: Boolean; + begin + Result := + (X > FHitPos.X + 8) or + (X < FHitPos.X - 8) or + (Y > FHitPos.Y + 8) or + (Y < FHitPos.Y - 8); + end; + +var + MustScroll: Boolean; + DeltaHorz, DeltaVert, HitCol, HitRow, SelCol, SelRow: Integer; + MousePt: TPoint; +begin + inherited; + MousePt := Point(X, Y); + if MouseCapture then + begin + case FGridState of + gsColSizing: + begin + SuggestSizing(csHide); + FSizingDest := X; + SuggestSizing(csShow); + end; + gsRowSizing: + begin + SuggestSizing(csHide); + FSizingDest := Y; + SuggestSizing(csShow); + end; + gsColMoveWaiting: if CanDrag then + begin + FDragOrigin := FHitCell.Col; + if BeginColDrag(FDragOrigin, MousePt) then + begin + ProcessDragWindow(FHitPos, MousePt, FDragOrigin, True, False); + FGridState := gsColMoving; + FDragDest := FDragOrigin; + SuggestDrag(csStart); + end; + end; + gsRowMoveWaiting: if CanDrag then + begin + FDragOrigin := FHitCell.Row; + if BeginRowDrag(FDragOrigin, MousePt) then + begin + ProcessDragWindow(FHitPos, MousePt, FDragOrigin, False, False); + FGridState := gsRowMoving; + FDragDest := FDragOrigin; + SuggestDrag(csStart); + end; + end; + gsSelecting, gsColMoving, gsRowMoving: + begin + if FGridState <> gsSelecting then + ProcessDragWindow(FHitPos, MousePt, cInvalidIndex, FGridState = gsColMoving, False); + if not FScrollTimer.Enabled and PointToCell(MousePt, True, + GridStateToInvisibleCells, HitCol, HitRow, SelCol, SelRow) then + begin + MustScroll := ScrollNeeded(HitCol, HitRow, DeltaHorz, DeltaVert); + if MustScroll then + begin + Scroll(cScrollDelta, cScrollDelta, DeltaHorz, DeltaVert, False); + FScrollTimer.Enabled := True; + end; + if FGridState = gsSelecting then + begin + InternalFindBaseCell(SelCol, SelRow, SelCol, SelRow); + SelectionMove(SelCol, SelRow, ssExpand, [sfMustUpdate]) + end else + DragMove(HitCol, HitRow, MousePt); + end; + end; + end; + end; + MouseOverCells; +end; + +procedure TKCustomGrid.MouseOverCells; +var + MousePt: TPoint; + HitCol, HitRow, BaseCol, BaseRow: Integer; +begin + MousePt := ScreenToClient(Mouse.CursorPos); + if not (FGridState in [gsColMoving, gsRowMoving]) and + ((goMouseOverCells in FOptions) or (FGridState <> gsNormal)) and + PtInRect(ClientRect, MousePt) and + PointToCell(MousePt, False, icNone, HitCol, HitRow, BaseCol, BaseRow) then + begin + InternalFindBaseCell(HitCol, HitRow, BaseCol, BaseRow); + if (BaseCol <> FMouseOver.Col) or (BaseRow <> FMouseOver.Row) then + begin + if FMouseOver.Col >= 0 then + begin + InvalidateCell(FMouseOver.Col, FMouseOver.Row); + MouseCellHint(FMouseOver.Col, FMouseOver.Row, False); + MouseLeaveCell(FMouseOver.Col, FMouseOver.Row); + end; + InvalidateCell(BaseCol, BaseRow); + if EditorMode and ( + (FMouseOver.Col = FEditorCell.Col) and (FMouseOver.Row = FEditorCell.Row) and + ((BaseCol <> FEditorCell.Col) or (BaseRow <> FEditorCell.Row)) + or + (BaseCol = FEditorCell.Col) and (BaseRow = FEditorCell.Row) and + ((FMouseOver.Col <> FEditorCell.Col) or (FMouseOver.Row <> FEditorCell.Row)) + ) then + FEditor.Invalidate; + FMouseOver := GridPoint(BaseCol, BaseRow); + MouseEnterCell(FMouseOver.Col, FMouseOver.Row); + if not MouseCapture then + begin + FHintCell := FMouseOver; + FCellHintTimer.Enabled := False; + FCellHintTimer.Interval := FMouseCellHintTime; + FCellHintTimer.Enabled := True; + end; + end; + end + else if FMouseOver.Col >= 0 then + begin + if EditorMode and (FMouseOver.Col = FEditorCell.Col) and (FMouseOver.Row = FEditorCell.Row) then + FEditor.Invalidate; + InvalidateCell(FMouseOver.Col, FMouseOver.Row); + MouseCellHint(FMouseOver.Col, FMouseOver.Row, False); + MouseLeaveCell(FMouseOver.Col, FMouseOver.Row); + FMouseOver := GridPoint(-1, -1); + end; +end; + +procedure TKCustomGrid.MouseUp(Button: TMouseButton; Shift: TShiftState; + X, Y: Integer); + + function NextSortMode(ASortMode: TKGridSortMode): TKGridSortMode; + begin + case FSortStyle of + ssDownUp: if ASortMode = smDown then Result := smUp else Result := smDown; + ssDownUpNone: + case ASortMode of + smDown: Result := smUp; + smUp: Result := smNone; + else + Result := smDown; + end; + else + case ASortMode of + smUp: Result := smDown; + smDown: Result := smNone; + else + Result := smUp; + end; + end; + end; + +var + BaseCol, BaseRow, BaseHitCol, BaseHitRow, HitCol, HitRow, Tmp: Integer; + CellFound: Boolean; + CellPt, MousePt: TPoint; +begin + inherited; + if Button = mbLeft then + begin + MousePt := Point(X, Y); + case FGridState of + gsColMoving, gsRowMoving: + begin + ProcessDragWindow(FHitPos, MousePt, -1, FGridState = gsColMoving, True); + SuggestDrag(csStop); + end; + gsColSizing, gsRowSizing: + SuggestSizing(csStop); + end; + if ColValid(FHitCell.Col) and RowValid(FHitCell.Row) and + PointToCell(MousePt, False, icNone, HitCol, HitRow, BaseCol, BaseRow) then + begin + InternalFindBaseCell(HitCol, HitRow, BaseCol, BaseRow); + InternalFindBaseCell(FHitCell.Col, FHitCell.Row, BaseHitCol, BaseHitRow); + CellFound := (BaseHitCol = BaseCol) and (BaseHitRow = BaseRow); + end else + CellFound := False; + case FGridState of + gsSelecting: + begin + ClampInView(Col, Row); + if CellFound then + MouseClickCell(BaseCol, BaseRow); + Click; + end; + gsColSortWaiting, gsRowSortWaiting, gsColMoveWaiting, gsRowMoveWaiting: + if CellFound then + begin + if not (ssShift in Shift) and ((FGridState = gsColSortWaiting) or (FGridState = gsRowMoveWaiting)) and + (goColSorting in FOptions) and (BaseCol = FRows[BaseRow].SortArrowIndex) then + SortCols(BaseRow, NextSortMode(Rows[BaseRow].SortMode)) + else if not (ssShift in Shift) and ((FGridState = gsRowSortWaiting) or (FGridState = gsColMoveWaiting)) and + (goRowSorting in FOptions) and (BaseRow = FCols[BaseCol].SortArrowIndex) then + SortRows(BaseCol, NextSortMode(Cols[BaseCol].SortMode)) + else + begin + InvalidateCell(BaseCol, BaseRow); + MouseClickCell(BaseCol, BaseRow); + Click; + end; + end; + gsClickWaiting: + if CellFound then + begin + InvalidateCell(BaseCol, BaseRow); + MouseClickCell(BaseCol, BaseRow); + Click; + end; + gsColMoving: + if EndColDrag(FDragOrigin, FDragDest, MousePt) and (FDragOrigin <> FDragDest) then + MoveCol(FDragOrigin, FDragDest) + else + InvalidateCol(FDragOrigin); + gsRowMoving: + if EndRowDrag(FDragOrigin, FDragDest, MousePt) and (FDragOrigin <> FDragDest) then + MoveRow(FDragOrigin, FDragDest) + else + InvalidateRow(FDragOrigin); + gsColSizing: + begin + case FSizingStyle of + ssLine, ssXORLine: + if EndColSizing(FSizingIndex, FSizingDest) and CellToPoint(FSizingIndex, 0, CellPt) then + begin + Tmp := FSizingDest - CellPt.X; + if not (goMouseCanHideCells in FOptions) then + Tmp := Max(Tmp, InternalGetMinColWidth(FSizingIndex)); + ColWidths[FSizingIndex] := Tmp; + end; + end; + UpdateDesigner; + end; + gsRowSizing: + begin + case FSizingStyle of + ssLine, ssXORLine: + if EndRowSizing(FSizingIndex, FSizingDest) and CellToPoint(0, FSizingIndex, CellPt) then + begin + Tmp := FSizingDest - CellPt.Y; + if not (goMouseCanHideCells in FOptions) then + Tmp := Max(Tmp, InternalGetMinRowHeight(FSizingIndex)); + RowHeights[FSizingIndex] := Tmp; + end; + end; + UpdateDesigner; + end + else + if CellFound then + InvalidateCell(BaseCol, BaseRow); + end; + FlagClear(cGF_ThroughClick); + FGridState := gsNormal; + end; +end; + +function TKCustomGrid.MouseToCell(X, Y: Integer; var ACol, ARow: Integer): Boolean; +var + DummyCol, DummyRow: Integer; +begin + Result := PointToCell(Point(X, Y), False, icNone, ACol, ARow, DummyCol, DummyRow); + if Result then + InternalFindBaseCell(ACol, ARow, ACol, ARow); +end; + +procedure TKCustomGrid.MoveCol(FromIndex, ToIndex: Integer); +var + I: Integer; +begin + if (FromIndex <> ToIndex) and ColValid(FromIndex) and ColValid(ToIndex) then + begin + if ToIndex > FromIndex then + for I := ToIndex downto FromIndex do + InternalExchangeCols(I, FromIndex) + else + for I := ToIndex to FromIndex do + InternalExchangeCols(I, FromIndex); + SelectionFix(FSelection); + UpdateAxes(True, cAll, False, cAll, []); + UpdateCellSpan; + ClearSortModeVert; + ColMoved(FromIndex, ToIndex); + end; +end; + +procedure TKCustomGrid.MoveRow(FromIndex, ToIndex: Integer); +var + I: Integer; +begin + if (FromIndex <> ToIndex) and RowValid(FromIndex) and RowValid(ToIndex) then + begin + if ToIndex > FromIndex then + for I := ToIndex downto FromIndex do + InternalExchangeRows(I, FromIndex) + else + for I := ToIndex to FromIndex do + InternalExchangeRows(I, FromIndex); + SelectionFix(FSelection); + UpdateAxes(False, cAll, True, cAll, []); + UpdateCellSpan; + ClearSortModeHorz; + RowMoved(FromIndex, ToIndex); + end; +end; + +procedure TKCustomGrid.MoveToNextCell; +var + ACol , ARow : Integer; +begin + ACol := FSelection.Col1; + ARow := FSelection.Row1; + InternalMove(ACol, ARow, DirectionToCommand(FMoveDirection), True, False); + if SelectionMove(ACol, ARow, ssInit, [sfMustUpdate, sfClampInView, sfDontCallSelectCell]) then + Click; +end; + +function TKCustomGrid.PageHeight: Integer; +var + Info: TKGridAxisInfo; +begin + Info := GetAxisInfoVert([aiFullVisBoundary]); + Result := Max(Info.FullVisCells - Info.FirstGridCell, 1); +end; + +function TKCustomGrid.PageWidth: Integer; +var + Info: TKGridAxisInfo; +begin + Info := GetAxisInfoHorz([aiFullVisBoundary]); + Result := Max(Info.FullVisCells - Info.FirstGridCell, 1); +end; + +procedure TKCustomGrid.PaintCell(ACanvas: TCanvas; ACol, ARow: Integer; AX, AY: Integer; APrinting: Boolean; ABlockRect: PRect); +var + R, ClipRect, TmpRect, TmpBlockRect: TRect; + CellBitmap: TBitmap; + TmpCanvas: TCanvas; + ClipCells: Boolean; + Info: TKGridAxisInfoBoth; +begin + if (ColWidths[ACol] > 0) and (RowHeights[ARow] > 0) then + if CellRect(ACol, ARow, R, True) then + begin + if not APrinting and ((goDoubleBufferedCells in FOptions) or DoubleBuffered) then + CellBitmap := TBitmap.Create + else + CellBitmap := nil; + try + if CellBitmap <> nil then + begin + TmpRect := Rect(0, 0, R.Right - R.Left, R.Bottom - R.Top); + CellBitmap.Width := TmpRect.Right; // SetSize not supported prior Delphi 2006 + CellBitmap.Height := TmpRect.Bottom; + TmpCanvas := CellBitmap.Canvas; + SelectClipRect(TmpCanvas.Handle, TmpRect); + ClipCells := False; + end else + begin + if ACanvas <> nil then + begin + TmpRect := Rect(AX, AY, AX + R.Right - R.Left, AY + R.Bottom - R.Top); + TmpCanvas := ACanvas; + SelectClipRect(TmpCanvas.Handle, TmpRect); + end else + begin + TmpRect := R; + TmpCanvas := Canvas; + end; + ClipCells := goClippedCells in FOptions; + end; + if ABlockRect <> nil then + TmpBlockRect := ABlockRect^ + else + TmpBlockRect := SelectionRect; + if CellBitmap <> nil then + OffsetRect(TmpBlockRect, -R.Left, -R.Top); + if (ACanvas = nil) or (ACanvas = Canvas) then + begin + Info := GetAxisInfoBoth([aiFixedParams]); + if (ARow >= FFixedRows) and (ACol < FFixedCols) then + ClipRect := Rect(0, Info.Vert.FixedBoundary, Info.Horz.FixedBoundary, Info.Vert.ClientExtent) + else if (ARow < FFixedRows) and (ACol >= FFixedCols) then + ClipRect := Rect(Info.Horz.FixedBoundary, 0, Info.Horz.ClientExtent, Info.Vert.FixedBoundary) + else if (ARow >= FFixedRows) and (ACol >= FFixedCols) then + ClipRect := Rect(Info.Horz.FixedBoundary, Info.Vert.FixedBoundary, Info.Horz.ClientExtent, Info.Vert.ClientExtent) + else + ClipRect := Rect(0, 0, Info.Horz.FixedBoundary, Info.Vert.FixedBoundary); + SelectClipRect(Canvas.Handle, ClipRect); + end; + InternalPaintCell(ACol, ARow, GetDrawState(ACol, ARow, HasFocus), TmpRect, TmpBlockRect, TmpCanvas, ClipCells, False); + if CellBitmap <> nil then + begin + Canvas.Lock; + try + Canvas.Draw(R.Left, R.Top, CellBitmap); + finally + Canvas.Unlock; + end; + end; + finally + CellBitmap.Free; + end; + end; +end; + +function TKCustomGrid.PaintCells(ACanvas: TCanvas; CellBitmap: TBitmap; MainClipRgn: HRGN; + FirstCol, LastCol, FirstRow, LastRow, X, Y, MaxX, MaxY: Integer; Printing, PaintSelection: Boolean; + const ABlockRect: TRect): TPoint; +var + I, J, I1, J1, XBack, YBack, + CHExtent, CHSpacing, CVExtent, CVSpacing, + HExtent, HSpacing, VExtent, VSpacing: Integer; + ClipCells, DrawLinesHorz, DrawLinesVert, GridFocused, HasHeader, HasFixedThemedCells, UseThemedCells: Boolean; + CellState: TKGridDrawState; + Span: TKGridCellSpan; + BorderRect, CellRect, TmpRect, TmpBlockRect: TRect; + TmpCanvas: TCanvas; +begin + GridFocused := Printing or HasFocus; + UseThemedCells := ThemedCells; + YBack := Y; + XBack := X; + // search for hidden merged cells first and update the FirstCol and FirstRow + // this is supposed to be faster for huge grids than to parse entire grid all the time + HExtent := FirstCol; + VExtent := FirstRow; + if FirstCol > 0 then // not for fixed cells + begin + I := FirstRow; + while (I <= LastRow) and (Y <= MaxY) do + begin + InternalFindBaseCell(FirstCol, I, I1, J1); + HExtent := Min(HExtent, I1); + VExtent := Min(VExtent, J1); + Inc(Y, InternalGetRowHeights(I) + InternalGetEffectiveRowSpacing(I)); + Inc(I); + end; + end; + if FirstRow > 0 then // not for fixed cells + begin + I := FirstCol; + while (I <= LastCol) and (X <= MaxX) do + begin + InternalFindBaseCell(I, FirstRow, I1, J1); + HExtent := Min(HExtent, I1); + VExtent := Min(VExtent, J1); + Inc(X, InternalGetColWidths(I) + InternalGetEffectiveColSpacing(I)); + Inc(I); + end; + end; + while FirstCol > HExtent do + begin + Dec(FirstCol); + Dec(XBack, InternalGetColWidths(FirstCol) + InternalGetEffectiveColSpacing(FirstCol)); + end; + while FirstRow > VExtent do + begin + Dec(FirstRow); + Dec(YBack, InternalGetRowHeights(FirstRow) + InternalGetEffectiveRowSpacing(FirstRow)); + end; + // now draw the grid + Y := YBack; + I := FirstRow; + while (I <= LastRow) and (Y <= MaxY) do + begin + X := XBack; + VExtent := InternalGetRowHeights(I); + VSpacing := InternalGetEffectiveRowSpacing(I); + J := FirstCol; + while (J <= LastCol) and (X <= MaxX) do + begin + HExtent := InternalGetColWidths(J); + HSpacing := InternalGetEffectiveColSpacing(J); + Span := InternalGetCellSpan(J, I); + if (Span.ColSpan > 0) and (Span.RowSpan > 0) then + begin + InternalGetHExtent(J, Span.ColSpan, CHExtent, CHSpacing); + InternalGetVExtent(I, Span.RowSpan, CVExtent, CVSpacing); + CellRect := Rect(X, Y, X + CHExtent, Y + CVExtent); + BorderRect := CellRect; + Inc(BorderRect.Bottom, CVSpacing); + Inc(BorderRect.Right, CHSpacing); + TmpRect := BorderRect; + if not Printing then + TranslateRectToDevice(ACanvas.Handle, TmpRect); + if Printing or RectInRegion(MainClipRgn, TmpRect) then + begin + if (CHExtent > 0) and (CVExtent > 0) then + begin + CellState := GetDrawState(J, I, GridFocused); + if Printing then + begin + CellState := CellState - [gdEdited, gdMouseDown, gdMouseOver]; + if not PaintSelection then + CellState := CellState - [gdSelected, gdFocused]; + end; + // default brush style for lines + ACanvas.Brush.Style := bsSolid; + // draw default grid + if (CHSpacing > 0) or (CVSpacing > 0) then + begin + DrawLinesHorz := CVSpacing > 0; + DrawLinesVert := CHSPacing > 0; + if gdFixed in CellState then + begin + HasHeader := (I < FFixedRows) and (goHeader in FOptions) and UseThemedCells; + HasFixedThemedCells := ((I < FFixedRows) or (J < FFixedCols)) and (gxFixedThemedCells in FOptionsEx) and UseThemedCells; + DrawLinesHorz := DrawLinesHorz and (goFixedHorzLine in FOptions) and not HasFixedThemedCells; + DrawLinesVert := DrawLinesVert and (goFixedVertLine in FOptions) and not (HasHeader or HasFixedThemedCells); + if UseThemedCells then + ACanvas.Brush.Color := FColors.FixedThemedCellLines + else + ACanvas.Brush.Color := FColors.FixedCellLines; + end else + begin + ACanvas.Brush.Color := FColors.CellLines; + DrawLinesHorz := DrawLinesHorz and (goHorzLine in FOptions); + DrawLinesVert := DrawLinesVert and (goVertLine in FOptions); + end; + if DrawLinesHorz then + begin + TmpRect := Rect(CellRect.Left, CellRect.Bottom, BorderRect.Right, BorderRect.Bottom); + ACanvas.FillRect(TmpRect); + end else + CellRect.Bottom := BorderRect.Bottom; + if DrawLinesVert then + begin + TmpRect := Rect(CellRect.Right, CellRect.Top, BorderRect.Right, CellRect.Bottom); + ACanvas.FillRect(TmpRect); + end else + CellRect.Right := BorderRect.Right; + end; + TmpBlockRect := ABlockRect; + if CellBitmap <> nil then + begin + TmpRect := Rect(0, 0, CellRect.Right - CellRect.Left, CellRect.Bottom - CellRect.Top); + CellBitmap.Width := TmpRect.Right; // SetSize not supported prior Delphi 2006 + CellBitmap.Height := TmpRect.Bottom; + TmpCanvas := CellBitmap.Canvas; + SelectClipRect(TmpCanvas.Handle, TmpRect); + ClipCells := False; + OffsetRect(TmpBlockRect, -CellRect.Left, -CellRect.Top); + end else + begin + TmpRect := CellRect; + TmpCanvas := ACanvas; + ClipCells := goClippedCells in FOptions; + end; + InternalPaintCell(J, I, CellState, TmpRect, TmpBlockRect, TmpCanvas, ClipCells, Printing); + if CellBitmap <> nil then + ACanvas.Draw(CellRect.Left, CellRect.Top, CellBitmap); + end + else if goIndicateHiddenCells in FOptions then + begin + TmpRect := BorderRect; + if (HExtent = 0) and (HSpacing > 0) then + begin + if (I = 0) and (CVExtent > FHCI.VBegin.Height) then + begin + ACanvas.Draw(TmpRect.Left, TmpRect.Top, FHCI.VBegin); + Inc(TmpRect.Top, FHCI.VBegin.Height); + end; + if (I = FRowCount - 1) and (CVExtent > FHCI.VEnd.Height) then + begin + Dec(TmpRect.Bottom, FHCI.VEnd.Height); + ACanvas.Draw(TmpRect.Left, TmpRect.Bottom, FHCI.HEnd); + end; + ACanvas.StretchDraw(TmpRect, FHCI.VCenter); + end; + if (VExtent = 0) and (VSpacing > 0) then + begin + if (J = 0) and (CHExtent > FHCI.HBegin.Width) then + begin + ACanvas.Draw(TmpRect.Left, TmpRect.Top, FHCI.HBegin); + Inc(TmpRect.Left, FHCI.HBegin.Width); + end; + if (J = FColCount - 1) and (CHExtent > FHCI.HEnd.Width) then + begin + Dec(TmpRect.Right, FHCI.HEnd.Width); + ACanvas.Draw(TmpRect.Right, TmpRect.Top, FHCI.HEnd); + end; + ACanvas.StretchDraw(TmpRect, FHCI.HCenter); + end; + end; + end; + end; + Inc(X, HExtent + HSpacing); + Inc(J); + end; + Inc(Y, VExtent + VSpacing); + Inc(I); + end; + Result := Point(X, Y); +end; + +procedure TKCustomGrid.PaintDragSuggestion(ACanvas: TCanvas); + + procedure DragSuggLine(X, Y, W, H: Integer); + begin + with ACanvas do + begin + Pen.Color := FColors.DragSuggestionLine; + Pen.Style := psSolid; + Pen.Width := 1; + Brush.Color := FColors.DragSuggestionBkGnd; + Brush.Style := bsSolid; + Rectangle(X, Y, X + W, Y + H); + end; + end; + +var + Len: Integer; + ArrowCopy: TKAlphaBitmap; + R: TRect; +begin + if GetDragRect(GetAxisInfoBoth([aiGridBoundary]), R) then + begin + case FDragStyle of + dsLayeredConst, dsLayeredFaded: + begin + ArrowCopy := TKAlphaBitmap.Create; + try + if FGridState = gsColMoving then + begin + ArrowCopy.CopyFrom(FDragArrow); + ArrowCopy.AlphaDrawTo(ACanvas, R.Left, R.Top); + Len := R.Bottom - R.Top - ArrowCopy.Height shl 1; + if Len > 0 then + begin + ArrowCopy.MirrorVert; + ArrowCopy.AlphaDrawTo(ACanvas, R.Left, R.Bottom - ArrowCopy.Height); + if Len > 6 then + DragSuggLine(R.Left + ArrowCopy.Width shr 1 - 1, + R.Top + ArrowCopy.Height + 1, 3, Len - 2); + end; + end else + begin + ArrowCopy.CopyFromRotated(FDragArrow); + ArrowCopy.AlphaDrawTo(ACanvas, R.Left, R.Top); + Len := R.Right - R.Left - ArrowCopy.Width shl 1; + if Len > 0 then + begin + ArrowCopy.MirrorHorz; + ArrowCopy.AlphaDrawTo(ACanvas, R.Right - ArrowCopy.Width, R.Top); + if Len > 6 then + DragSuggLine(R.Left + ArrowCopy.Width + 1, + R.Top + ArrowCopy.Height shr 1 - 1, Len - 2, 3); + end; + end; + finally + ArrowCopy.Free; + end; + end; + dsLine, dsXORLine: + begin + with ACanvas do + begin + // prevent rounded caps + Pen.Width := 1; + if FDragStyle = dsLine then + Pen.Color := clRed + else + begin + Pen.Mode := pmXOR; + Pen.Color := clWhite; + end; + try + if FGridState = gsColMoving then + begin + for Len := 0 to 4 do + begin + ACanvas.MoveTo(R.Left + Len, R.Top); + ACanvas.LineTo(R.Left + Len, R.Bottom); + end; + end else + begin + for Len := 0 to 4 do + begin + ACanvas.MoveTo(R.Left, R.Top + Len); + ACanvas.LineTo(R.Right, R.Top + Len); + end; + end; + finally + Pen.Mode := pmCopy; + end; + end; + end; + end; + end; +end; + +procedure TKCustomGrid.PaintHeaderAlignment(ACanvas: TCanvas; ARect: TRect); +begin + {$IFDEF USE_THEMES} + if ThemedCells then with ThemeServices do + begin + Inc(ARect.Bottom); + DrawElement(ACanvas.Handle, GetElementDetails(thHeaderItemRightNormal), ARect) + end else + {$ENDIF} + begin + ACanvas.Brush.Color := FColors.FixedCellBkGnd; + Dec(ARect.Bottom); + ACanvas.FillRect(ARect); + if {$IFDEF FPC}not Flat{$ELSE}Ctl3D{$ENDIF} then + {$IFDEF USE_WINAPI} + // looks somewhat better though + DrawEdge(ACanvas.Handle, ARect, BDR_RAISEDINNER, BF_LEFT or BF_TOP or BF_BOTTOM or BF_SOFT); + {$ELSE} + DrawEdges(ACanvas, ARect, cl3DHilight, cl3DShadow, BF_LEFT or BF_TOP or BF_BOTTOM); + {$ENDIF} + ACanvas.Brush.Color := FColors.FixedCellLines; + ACanvas.FillRect(Rect(ARect.Left, ARect.Bottom, ARect.Right, ARect.Bottom + 1)); + end; +end; + +procedure TKCustomGrid.PaintPage; + + procedure Axis(const Info: TKGridAxisInfo; CanvasExtent, Page, SelStart, SelEnd: Integer; + SelOnly, FitToPage: Boolean; out FirstIndex, LastIndex, PageExtent: Integer); + var + I, Extent, StartIndex, EndIndex, Pages: Integer; + begin + Pages := 1; + PageExtent := 0; + if SelOnly then + begin + StartIndex := SelStart; + EndIndex := SelEnd; + end else + begin + StartIndex := 0; + EndIndex := Info.TotalCellCount - 1; + end; + FirstIndex := StartIndex; + LastIndex := StartIndex; + for I := StartIndex to EndIndex do + begin + Extent := Info.CellExtent(I) + Info.EffectiveSpacing(I); + if FitToPage or (PageExtent + Extent < CanvasExtent) or (I = 0) then + Inc(PageExtent, Extent) + else + begin + FirstIndex := LastIndex; + LastIndex := I; + if Page = Pages then + begin + Dec(LastIndex); + Exit; + end; + Inc(Pages); + PageExtent := Extent; + end; + end; + FirstIndex := LastIndex; + LastIndex := EndIndex; + end; + +var + FirstCol, FirstRow, LastCol, LastRow, OutlineWidth, OutlineHeight, AreaWidth, AreaHeight: Integer; + FitToPage, SelOnly{$IFDEF LCLQT}, AThemedCells{$ENDIF}: Boolean; + TmpRect, TmpRect1: TRect; + MainClipRgn: HRGN; + R: TKGridRect; + APageSetup: TKPrintPageSetup; +// CellBitmap: TBitmap; +begin + R := InternalExpandGridRect(Selection); + NormalizeGridRect(R); + APageSetup := PageSetup; + FitToPage := poFitToPage in APageSetup.Options; + SelOnly := APageSetup.Range = prSelectedOnly; + AreaWidth := Round(APageSetup.PaintAreaWidth / APageSetup.CurrentScale); + AreaHeight := Round(APageSetup.PaintAreaHeight / APageSetup.CurrentScale); + Axis(GetAxisInfoHorz([]), AreaWidth, (APageSetup.CurrentPage - 1) mod APageSetup.HorzPageCount + 1, + R.Col1, R.Col2, SelOnly, FitToPage, FirstCol, LastCol, OutlineWidth); + Axis(GetAxisInfoVert([]), AreaHeight, (APageSetup.CurrentPage - 1) div APageSetup.HorzPageCount + 1, + R.Row1, R.Row2, SelOnly, False, FirstRow, LastRow, OutlineHeight); + if poUseColor in APageSetup.Options then + FColors.ColorScheme := csNormal + else + FColors.ColorScheme := csGrayScale; + TmpRect := Rect(0, 0, OutlineWidth, OutlineHeight); + TmpRect1 := Rect(0, 0, AreaWidth, AreaHeight); + IntersectRect(TmpRect, TmpRect, TmpRect1); + TranslateRectToDevice(APageSetup.Canvas.Handle, TmpRect); +{$IFDEF LCLQT} + AThemedCells := goThemedCells in FOptions; + Exclude(FOptions, goThemedCells); +{$ENDIF} + MainClipRgn := CreateRectRgnIndirect(TmpRect); +// if goDoubleBufferedCells in FOptions then +// CellBitmap := TBitmap.Create +// else +// CellBitmap := nil; + try + SelectClipRgn(APageSetup.Canvas.Handle, MainClipRgn); + TmpRect := SelectionRect; + if SelOnly then + OffsetRect(TmpRect, -TmpRect.Left, -TmpRect.Top); + PaintCells(PageSetup.Canvas, nil, MainClipRgn, FirstCol, LastCol, FirstRow, LastRow, + 0, 0, OutlineWidth, OutlineHeight, True, poPaintSelection in APageSetup.Options, TmpRect); + finally + DeleteObject(MainClipRgn); +// CellBitmap.Free; + {$IFDEF LCLQT} + if AThemedCells then + Include(FOptions, goThemedCells); + {$ENDIF} + end; +end; + +procedure TKCustomGrid.PaintSizingSuggestion(ACanvas: TCanvas); +var + Info: TKGridAxisInfo; + I: Integer; +begin + case FSizingStyle of + ssLine, ssXORLine: + begin + with ACanvas do + begin + Pen.Width := 1; + if FSizingStyle = ssLine then + Pen.Color := clRed + else + begin + Pen.Mode := pmXOR; + Pen.Color := clWhite; + end; + try + case FGridState of + gsColSizing: + begin + Info := GetAxisInfoVert([aiGridBoundary]); + for I := 0 to 1 do + begin + ACanvas.MoveTo(FSizingDest + I, 0); + ACanvas.LineTo(FSizingDest + I, Info.GridBoundary); + end; + end; + gsRowSizing: + begin + Info := GetAxisInfoHorz([aiGridBoundary]); + for I := 0 to 1 do + begin + ACanvas.MoveTo(0, FSizingDest + I); + ACanvas.LineTo(Info.GridBoundary, FSizingDest + I); + end; + end; + end; + finally + Pen.Mode := pmCopy; + end; + end; + end; + end; +end; + +procedure TKCustomGrid.PaintToCanvas(ACanvas: TCanvas); +var + I, Bottom, ClientH, ClientW, GridW, GridH, SaveIndex: Integer; + TmpExtent: TPoint; + TmpRect: TRect; + CurClipRgn, MainClipRgn: HRGN; + DC: HDC; + CellBitmap: TBitmap; + Info: TKGridAxisInfoBoth; + TmpBlockRect: TRect; +begin + DC := ACanvas.Handle; + SaveIndex := SaveDC(DC); // don't delete + ACanvas.Lock; + try + if Enabled or (FDisabledDrawStyle = ddNormal) then + FColors.ColorScheme := csNormal + else if FDisabledDrawStyle = ddGrayed then + FColors.ColorScheme := csGrayed + else + FColors.ColorScheme := csBright; + ClientH := ClientHeight; + ClientW := ClientWidth; + Info := GetAxisInfoBoth([aiFixedParams]); + GridW := 0; GridH := 0; + TmpExtent := Point(0, 0); + if (goDoubleBufferedCells in FOptions) and not DoubleBuffered then + CellBitmap := TBitmap.Create + else + CellBitmap := nil; + MainClipRgn := CreateEmptyRgn; + CurClipRgn := CreateEmptyRgn; + try + TmpBlockRect := SelectionRect; + if GetClipRgn(DC, MainClipRgn) <> 1 then + begin + DeleteObject(MainClipRgn); + TmpRect := Rect(0, 0, ClientW, ClientH); + TranslateRectToDevice(DC, TmpRect); + MainClipRgn := CreateRectRgnIndirect(TmpRect); + end; + // draw clipped selectable cells first (to avoid some GTK clipping problems) + TmpRect := Rect(Info.Horz.FixedBoundary, Info.Vert.FixedBoundary, ClientW, ClientH); + if not IsRectEmpty(TmpRect) then + begin + TranslateRectToDevice(DC, TmpRect); + if ExtSelectClipRectEx(DC, TmpRect, RGN_AND, CurClipRgn, MainClipRgn) then + begin + TmpExtent := PaintCells(ACanvas, CellBitmap, CurClipRgn, FTopLeft.Col, FColCount - 1, FTopLeft.Row, FRowCount - 1, + Info.Horz.FixedBoundary - FScrollOffset.X, Info.Vert.FixedBoundary - FScrollOffset.Y, ClientW, ClientH, False, True, TmpBlockRect); + end; + end; + GridW := Max(GridW, TmpExtent.X); GridH := Max(GridH, TmpExtent.Y); + // clipped fixed rows + TmpRect := Rect(Info.Horz.FixedBoundary, 0, ClientW, Info.Vert.FixedBoundary); + if not IsRectEmpty(TmpRect) then + begin + TranslateRectToDevice(DC, TmpRect); + if ExtSelectClipRectEx(DC, TmpRect, RGN_AND, CurClipRgn, MainClipRgn) then + TmpExtent := PaintCells(ACanvas, CellBitmap, CurClipRgn, FTopLeft.Col, FColCount - 1, 0, FFixedRows - 1, + Info.Horz.FixedBoundary - FScrollOffset.X, 0, ClientW, ClientH, False, True, TmpBlockRect); + end; + GridW := Max(GridW, TmpExtent.X); GridH := Max(GridH, TmpExtent.Y); + // clipped fixed columns + TmpRect := Rect(0, Info.Vert.FixedBoundary, Info.Horz.FixedBoundary, ClientH); + if not IsRectEmpty(TmpRect) then + begin + TranslateRectToDevice(DC, TmpRect); + if ExtSelectClipRectEx(DC, TmpRect, RGN_AND, CurClipRgn, MainClipRgn) then + TmpExtent := PaintCells(ACanvas, CellBitmap, CurClipRgn, 0, FFixedCols - 1, FTopLeft.Row, FRowCount - 1, 0, + Info.Vert.FixedBoundary - FScrollOffset.Y, ClientW, ClientH, False, True, TmpBlockRect); + end; + GridW := Max(GridW, TmpExtent.X); GridH := Max(GridH, TmpExtent.Y); + // non-clipped fixed cells + TmpRect := Rect(0, 0, Info.Horz.FixedBoundary, Info.Vert.FixedBoundary); + if not IsRectEmpty(TmpRect) then + begin + TranslateRectToDevice(DC, TmpRect); + if ExtSelectClipRectEx(DC, TmpRect, RGN_AND, CurClipRgn, MainClipRgn) then + TmpExtent := PaintCells(ACanvas, CellBitmap, CurClipRgn, 0, FFixedCols - 1, 0, FFixedRows - 1, + 0, 0, ClientW, ClientH, False, True, TmpBlockRect); + end; + GridW := Max(GridW, TmpExtent.X); GridH := Max(GridH, TmpExtent.Y); + finally + FinalizePrevRgn(DC, MainClipRgn); + DeleteObject(CurClipRgn); + CellBitmap.Free; + end; + // draw a focus rectangle around cells in goRangeSelect and goRowSelect mode + if not (csDesigning in ComponentState) and (goDrawFocusSelected in FOptions) and + (FOptions * [goRangeSelect, goRowSelect] <> []) and Focused and not EditorMode then + begin + // to ensure coming DrawFocusRect will be painted correctly: + SetBkColor(DC, $FFFFFF); + SetTextColor(DC, 0); + ACanvas.DrawFocusRect(TmpBlockRect); + end; + // default color for client area parts not consumed by cells + ACanvas.Brush.Style := bsSolid; + // fill window client area parts not consumed by cells + if GridH < ClientH then + begin + ACanvas.Brush.Color := Color; + ACanvas.FillRect(Rect(0, GridH, GridW, ClientH)); + end; + if GridW < ClientW then + begin + if (goHeader in FOptions) and (goHeaderAlignment in FOptions) and (FFixedRows > 0) then + begin + Bottom := 0; + for I := 0 to FFixedRows - 1 do + Inc(Bottom, InternalGetRowHeights(I) + InternalGetEffectiveRowSpacing(I)); + PaintHeaderAlignment(ACanvas, Rect(GridW, 0, ClientW, Bottom)); + end else + Bottom := 0; + ACanvas.Brush.Color := Color; + ACanvas.FillRect(Rect(GridW, Bottom, ClientW, ClientH)); + end; + if FGridState in [gsColMoving, gsRowMoving] then PaintDragSuggestion(ACanvas); + if FGridState in [gsColSizing, gsRowSizing] then PaintSizingSuggestion(ACanvas); + finally + RestoreDC(DC, SaveIndex); + Canvas.Unlock; + end; +end; + +function TKCustomGrid.PointToCell(Point: TPoint; OutSide: Boolean; + InvisibleCells: TKGridInvisibleCells; out HitCol, HitRow, SelCol, SelRow: Integer): Boolean; + + function Axis1(const Info: TKGridAxisInfo; Coord: Integer; InVis1, InVis2: TKGridInvisibleCells): Integer; + var + I, PtBegin, PtEnd, PtEOFixed: Integer; + begin + Result := -1; + // check fixed cells + I := 0; + PtBegin := 0; + while (I < Info.FixedCellCount) and (Result < 0) do + begin + PtEnd := PtBegin + Info.CellExtent(I) + Info.EffectiveSpacing(I); + if (InvisibleCells in [icNone, InVis1]) {or (Info.FixedSelectable and (Info.FirstGridCell = Info.FixedCellCount)) } and + (Coord >= PtBegin) and (Coord < PtEnd) then + Result := I; + PtBegin := PtEnd; + Inc(I); + end; + if (Result < 0) then + begin + PtEOFixed := PtBegin - Info.ScrollOffset; + I := Info.FirstGridCell; + if (Coord < PtEOFixed) and (InvisibleCells in [InVis2, icCells]) then + begin + // check the invisible cells to the left or top + PtEnd := PtEOFixed; + while (I > Info.FixedCellCount) and (Result < 0) do + begin + Dec(I); + PtBegin := PtEnd - Info.CellExtent(I) - Info.EffectiveSpacing(I); + if (Coord >= PtBegin) and (Coord < PtEnd) then + Result := I; + PtEnd := PtBegin; + end; + if OutSide and (Result < 0) then + if Info.FixedSelectable then + Result := 0 + else + Result := Info.FixedCellCount; + end else + begin + // check visible cells and invisible ones to the right or bottom + PtBegin := PtEOFixed; + while (I < Info.TotalCellCount) and (Result < 0) do + begin + PtEnd := PtBegin + Info.CellExtent(I) + Info.EffectiveSpacing(I); + if (Coord >= PtBegin) and (Coord < PtEnd) then + Result := I; + PtBegin := PtEnd; + Inc(I); + end; + if OutSide and (Result < 0) then + Result := Info.TotalCellCount - 1; + end; + end; + end; + + function Axis2(const Info: TKGridAxisInfo; Index: Integer): Integer; + begin + if Index = Info.FixedCellCount then + begin + // some first nonfixed columns or rows may be hidden, so take first visible column/row + while (Index < Info.TotalCellCount) and (Info.CellExtent(Index) = 0) do + Inc(Index); + if Index >= Info.TotalCellCount then + Index := Info.FixedCellCount; + end + else if Index = Info.TotalCellCount - 1 then + begin + // some last columns or rows may be hidden, so take last visible column/row + while (Index >= Info.FixedCellCount) and (Info.CellExtent(Index) = 0) do + Dec(Index); + if Index < Info.FixedCellCount then + Index := Info.TotalCellCount - 1; + end; + Result := Index; + end; + +var + Info: TKGridAxisInfo; +begin + Result := False; + Info := GetAxisInfoHorz([]); + HitCol := Axis1(Info, Point.X, icFixedRows, icFixedCols); + if HitCol >= 0 then + begin + if OutSide then SelCol := Axis2(Info ,HitCol) else SelCol := HitCol; + Info := GetAxisInfoVert([]); + HitRow := Axis1(Info, Point.Y, icFixedCols, icFixedRows); + if HitRow >= 0 then + begin + if OutSide then SelRow := Axis2(Info, HitRow) else SelRow := HitRow; + Result := True; + end; + end +end; + +function TKCustomGrid.PointToSizing(Point: TPoint; var State: TKGridState; + var Index, Pos: Integer): Boolean; + + function AxisSizing(const Info: TKGridAxisInfo; Coord: Integer; + var Index, Pos: Integer): Boolean; + const + cDelta = 3; + var + I, ICopy, Dummy, ES, Line, StartCell: Integer; + begin + Result := False; + if (Info.FullVisCells < Info.GridCells) and + (Coord >= Info.ClientExtent - cDelta) and (Coord <= Info.ClientExtent) then + begin + Index := Info.FullVisCells; + Pos := Info.ClientExtent; + Result := True; + end else + begin + Line := Info.FullVisBoundary; + StartCell := Info.FullVisCells - 1; + for I := StartCell downto Info.FirstGridCell do + begin + ES := Info.EffectiveSpacing(I); + ICopy := I; + if ((I < StartCell) or not Info.AlignLastCell) and + ({(Info.CellExtent(I) <> 0) or (I = StartCell) and} Info.CanResize(ICopy, Dummy)) and + (Coord >= Line - ES - cDelta) and (Coord <= Line + cDelta) then + begin + Index := I; + Pos := Line; + Result := True; + Break; + end; + Dec(Line, Info.CellExtent(I) + ES); + end; + if not Result then + begin + Line := Info.FixedBoundary; + for I := Info.FixedCellCount - 1 downto 0 do + begin + ES := Info.EffectiveSpacing(I); + ICopy := I; + if (Coord >= Line - ES - cDelta) and (Coord <= Line + cDelta) and Info.CanResize(ICopy, Dummy) then + begin + Index := I; + Pos := Line; + Result := True; + Break; + end; + Dec(Line, Info.CellExtent(I) + ES); + end; + end; + end; + end; + +var + EffColSizing, EffRowSizing: Boolean; + Info: TKGridAxisInfoBoth; +begin + Result := False; + EffColSizing := (goColSizing in FOptions) or (csDesigning in ComponentState); + EffRowSizing := (goRowSizing in FOptions) or (csDesigning in ComponentState); + if EffColSizing or EffRowSizing then + begin + Info := GetAxisInfoBoth([aiFullVisBoundary, aiGridBoundary]); + if EffColSizing and AxisSizing(Info.Horz, Point.X, Index, Pos) and + ((Point.Y < Info.Vert.FixedBoundary) or (Point.Y < Info.Vert.GridBoundary) and + (InternalGetColWidths(Index) = 0)) then + begin + Result := True; + State := gsColSizing; + end + else if EffRowSizing and AxisSizing(Info.Vert, Point.Y, Index, Pos) and + ((Point.X < Info.Horz.FixedBoundary) or (Point.X < Info.Horz.GridBoundary) and + (InternalGetRowHeights(Index) = 0)) then + begin + Result := True; + State := gsRowSizing; + end; + end; +end; + +procedure TKCustomGrid.ProcessDragWindow(const PtIni, PtCur: TPoint; Index: Integer; ColDrag, Hide: Boolean); +var + MaxWidth, MaxHeight: Integer; + Alpha: Byte; + Gradient: Boolean; + RClip, RSrc, RDest: TRect; + P: TKGridCoord; + Form: TCustomForm; + Info: TKGridAxisInfoBoth; +begin + if FDragStyle in [dsLayeredConst, dsLayeredFaded] then + begin + if Index >= 0 then + begin + // (re)initialize drag image bitmaps + if ColDrag then + P := GridPoint(Index, 0) + else + P := GridPoint(0, Index); + if CellToPoint(P.Col, P.Row, RSrc.TopLeft) then + begin + Form := GetParentForm(Self); + if Form <> nil then + begin + MaxWidth := Min(ClientWidth, Form.ClientWidth - Left); + MaxHeight := Min(ClientHeight, Form.ClientHeight - Top); + end else + begin + MaxWidth := ClientWidth; + MaxHeight := ClientHeight; + end; + Info := GetAxisInfoBoth([aiGridBoundary]); + if ColDrag then + begin + RSrc.Right := RSrc.Left + GetColWidths(Index); + RSrc.Bottom := Info.Vert.GridBoundary; + RClip := Rect(Info.Horz.FixedBoundary, 0, MaxWidth, MaxHeight); + end else + begin + RSrc.Bottom := RSrc.Top + GetRowHeights(Index); + RSrc.Right := Info.Horz.GridBoundary; + RClip := Rect(0, Info.Vert.FixedBoundary, MaxWidth, MaxHeight); + end; + if IntersectRect(RDest, RSrc, RClip) then + begin + if FDragWindow = nil then FDragWindow := TKDragWindow.Create; + if FDragStyle = dsLayeredFaded then + begin + Alpha := $E0; + Gradient := True; + end else + begin + Alpha := $80; + Gradient := False; + end; + EditorMode := False; + Update; + FDragWindow.Show(Self, RDest, PtIni, PtCur, Alpha, Gradient); + end; + end; + end + else if FDragWindow <> nil then + begin + if Hide then + FDragWindow.Hide + else + FDragWindow.Move(PtCur); + end; + end; +end; + +procedure TKCustomGrid.RealizeCellClass; +var + I, J: Integer; + Cell, TmpCell: TKGridCell; + UpdateNeeded: Boolean; +begin + if Assigned(FCells) then + begin + UpdateNeeded := False; + for I := 0 to FColCount - 1 do + for J := 0 to FRowCount - 1 do + begin + Cell := FCells[J, I]; + if (Cell <> nil) and (Cell.ClassType <> FCellClass) then + begin + TmpCell := FCellClass.Create(Self); + FlagSet(cGF_GridUpdates); + try + TmpCell.Assign(Cell); // copy known properties + finally + FlagClear(cGF_GridUpdates); + end; + Cell.Free; + FCells[J, I] := TmpCell; + UpdateNeeded := True; + end; + end; + if UpdateNeeded then + Invalidate; + end; +end; + +procedure TKCustomGrid.RealizeColClass; +var + I: Integer; + TmpItem: TKGridAxisItem; + UpdateNeeded: Boolean; +begin + UpdateNeeded := False; + for I := 0 to FColCount - 1 do + if FCols[I].ClassType <> FColClass then + begin + TmpItem := FColClass.Create(Self); + FlagSet(cGF_GridUpdates); + try + TmpItem.Assign(FCols[I]); + TmpItem.InitialPos := FCols[I].InitialPos; + finally + FlagClear(cGF_GridUpdates); + end; + FCols[I].Free; + FCols[I] := TmpItem; + UpdateNeeded := True; + end; + if UpdateNeeded then + UpdateAxes(True, cAll, False, cAll, []); +end; + +procedure TKCustomGrid.RealizeRowClass; +var + I: Integer; + TmpItem: TKGridAxisItem; + UpdateNeeded: Boolean; +begin + UpdateNeeded := False; + for I := 0 to FRowCount - 1 do + if FRows[I].ClassType <> FRowClass then + begin + TmpItem := FRowClass.Create(Self); + FlagSet(cGF_GridUpdates); + try + TmpItem.Assign(FRows[I]); + TmpItem.InitialPos := FRows[I].InitialPos; + finally + FlagClear(cGF_GridUpdates); + end; + FRows[I].Free; + FRows[I] := TmpItem; + UpdateNeeded := True; + end; + if UpdateNeeded then + UpdateAxes(False, cAll, True, cAll, []); +end; + +procedure TKCustomGrid.ReadColWidths(Reader: TReader); +var + I: Integer; +begin + with Reader do + begin + ReadListBegin; + for I := 0 to FColCount - 1 do ColWidths[I] := ReadInteger; + ReadListEnd; + end; +end; + +procedure TKCustomGrid.ReadRowHeights(Reader: TReader); +var + I: Integer; +begin + with Reader do + begin + ReadListBegin; + for I := 0 to FRowCount - 1 do RowHeights[I] := ReadInteger; + ReadListEnd; + end; +end; + +procedure TKCustomGrid.ResetTopLeft; +begin + if (FTopLeft.Col <> FFixedCols) or (FTopLeft.Row <> FFixedRows) then + begin + FTopLeft := GridPoint(FFixedCols, FFixedRows); + Invalidate; + TopLeftChanged; + end; +end; + +procedure TKCustomGrid.RowHeightsChanged(ARow: Integer); +begin + if Assigned(FOnRowHeightsChanged) then + FOnRowHeightsChanged(Self) + else if Assigned(FOnRowHeightsChangedEx) then + FOnRowHeightsChangedEx(Self, ARow) +end; + +procedure TKCustomGrid.RowMoved(FromIndex, ToIndex: Integer); +begin + if Assigned(FOnRowMoved) then + FOnRowMoved(Self, FromIndex, ToIndex); +end; + +function TKCustomGrid.RowSelectable(ARow: Integer): Boolean; +begin + Result := (ARow >= FFixedRows) and (ARow < FRowCount); +end; + +function TKCustomGrid.RowSelected(ARow: Integer): Boolean; +begin + Result := RowInGridRect(ARow, FSelection); +end; + +function TKCustomGrid.RowValid(ARow: Integer): Boolean; +begin + Result := (ARow >= 0) and (ARow < FRowCount); +end; + +procedure TKCustomGrid.SafeSetFocus; +var + Form: TCustomForm; +begin + Form := GetParentForm(Self); + if (Form <> nil) and Form.Visible and Form.Enabled and not (csDestroying in Form.ComponentState) then + if EditorMode and FEditor.Enabled then + Form.ActiveControl := FEditor + else if Visible and Enabled then + Form.ActiveControl := Self; +end; + +procedure TKCustomGrid.Scroll(CodeHorz, CodeVert, DeltaHorz, DeltaVert: Integer; + CallUpdateEditor: Boolean); + + function Axis(Code: Cardinal; HasScrollBar: Boolean; ScrollCode: Cardinal; Delta: Integer; + ScrollMode: TKGridScrollMode; const Info: TKGridAxisInfo; + var FirstGridCell, ScrollPos, ScrollOffset: Integer): Boolean; + + procedure DoScroll(ADelta: Integer; OnlyIfGreater: Boolean = False); + var + I, TotalExtent: Integer; + begin + I := 0; + ScrollOffset := 0; + if ADelta > 0 then + begin + while (I < ADelta) and (FirstGridCell < Info.FirstGridCellExtent) do + begin + TotalExtent := Info.CellExtent(FirstGridCell) + Info.EffectiveSpacing(FirstGridCell); + if OnlyIfGreater then + if I + TotalExtent > ADelta then + begin + if ScrollMode = smSmooth then + ScrollOffset := ADelta - I; + Break; + end; + Inc(I, TotalExtent); + Inc(FirstGridCell); + end; + end + else if ADelta < 0 then + begin + while (I > ADelta) and (FirstGridCell > Info.FixedCellCount) do + begin + Dec(FirstGridCell); + TotalExtent := Info.CellExtent(FirstGridCell) + Info.EffectiveSpacing(FirstGridCell); + if OnlyIfGreater then + if I - TotalExtent < ADelta then + begin + if ScrollMode = smSmooth then + begin + ScrollOffset := ADelta - I + TotalExtent; + Dec(ScrollPos, TotalExtent); + end else + Inc(FirstGridCell); + Break; + end; + Dec(I, TotalExtent); + end; + end; + Inc(ScrollPos, I); + end; + + var + OldScrollPos, OldScrollOffset: Integer; + SI: TScrollInfo; + begin + Result := False; + if HasScrollBar then + begin + FillChar(SI, SizeOf(TScrollInfo), 0); + SI.cbSize := SizeOf(TScrollInfo); + SI.fMask := SIF_PAGE or SIF_RANGE or SIF_TRACKPOS; + GetScrollInfo(Handle, Code, SI); + {$IF DEFINED(LCLGTK2)} + {.$WARNING "scrollbar arrows still not working properly on GTK2 in some cases!"} + SI.nTrackPos := Delta; + {$IFEND} + end; + OldScrollPos := ScrollPos; + OldScrollOffset := ScrollOffset; + if ScrollCode = Cardinal(cScrollDelta) then + DoScroll(Delta) // in Pixels! + else if HasScrollBar then + case ScrollCode of + SB_TOP: + begin + FirstGridCell := Info.FixedCellCount; + ScrollPos := SI.nMin; + ScrollOffset := 0; + end; + SB_BOTTOM: + begin + FirstGridCell := Info.FirstGridCellExtent; + ScrollPos := SI.nMax - Max(SI.nPage - 1, 0); + ScrollOffset := 0; + end; + SB_LINEUP: DoScroll(ScrollDeltaFromDelta(Info, -1)); + SB_LINEDOWN: DoScroll(ScrollDeltaFromDelta(Info, 1)); + SB_PAGEUP: DoScroll(-SI.nPage); + SB_PAGEDOWN: DoScroll(SI.nPage); + SB_THUMBTRACK, SB_THUMBPOSITION: DoScroll(SI.nTrackPos - ScrollPos, True); + end; + FirstGridCell := MinMax(FirstGridCell, Info.FixedCellCount, Info.FirstGridCellExtent); + if (ScrollPos <> OldScrollPos) or (ScrollOffset <> OldScrollOffset) then + begin + if HasScrollBar then + begin + FillChar(SI, SizeOf(TScrollInfo), 0); + SI.cbSize := SizeOf(TScrollInfo); + SI.fMask := SIF_POS; + SI.nPos := ScrollPos + ScrollOffset; + SetScrollInfo(Handle, Code, SI, True); + end; + Result := True; + end; + end; + +var + Horz, Vert: Boolean; //because of $B- + OldTopLeft: TKGridCoord; +begin + OldTopLeft := FTopLeft; + Horz := Axis(SB_HORZ, FScrollBars in [ssHorizontal, ssBoth], CodeHorz, DeltaHorz, + FScrollModeHorz, GetAxisInfoHorz([]), FTopLeft.Col, FScrollPos.x, FScrollOffset.X); + Vert := Axis(SB_VERT, FScrollBars in [ssVertical, ssBoth], CodeVert, DeltaVert, + FScrollModeVert, GetAxisInfoVert([]), FTopLeft.Row, FScrollPos.y, FScrollOffset.Y); + if Horz or Vert then + begin + if Horz then + InvalidateCols(FFixedCols); + if Vert then + InvalidateRows(FFixedRows); + if CallUpdateEditor then + UpdateEditor(Flag(cGF_EditorModeActive)); + if (OldTopLeft.Col <> FTopLeft.Col) or (OldTopLeft.Row <> FTopLeft.Row) then + TopLeftChanged; + end; +end; + +procedure TKCustomGrid.ScrollBy(AColCount, ARowCount: Integer); +begin + Scroll(cScrollDelta, cScrollDelta, + ScrollDeltaFromDelta(GetAxisInfoHorz([]), AColCount), + ScrollDeltaFromDelta(GetAxisInfoVert([]), ARowCount), + True); +end; + +function TKCustomGrid.ScrollDeltaFromDelta(const Info: TKGridAxisInfo; ADelta: Integer): Integer; +var + I, CellExtent, MaxIndex: Integer; +begin + Result := 0; + I := Info.FirstGridCell; + MaxIndex := Info.FirstGridCell + ADelta; + if ADelta > 0 then + begin + while (I < Info.FirstGridCellExtent) do + begin + CellExtent := Info.CellExtent(I); + Inc(Result, CellExtent + Info.EffectiveSpacing(I)); + Inc(I); + if (CellExtent > 0) and (I >= MaxIndex) then + Break; + end; + end + else if ADelta < 0 then + begin + while (I > Info.FixedCellCount) do + begin + Dec(I); + CellExtent := Info.CellExtent(I); + Dec(Result, CellExtent + Info.EffectiveSpacing(I)); + if (CellExtent > 0) and (I <= MaxIndex) then + Break; + end; + end; +end; + +function TKCustomGrid.ScrollNeeded(ACol, ARow: Integer; + out DeltaHorz, DeltaVert: Integer): Boolean; + + function Axis(Info: TKGridAxisInfo; Index, Span: Integer; var Delta: Integer): Boolean; + var + I, Extent: Integer; + begin + Result := False; + Delta := 0; + if Index < Info.FixedCellCount then Exit; + if Index = Info.FirstGridCell then + begin + if Info.ScrollOffset <> 0 then + Result := True; + end; + if Index < Info.FirstGridCell then + begin + for I := Info.FirstGridCell - 1 downto Index do + Dec(Delta, Info.CellExtent(I) + Info.EffectiveSpacing(I)); + Result := True; + end else + begin + Extent := Info.FixedBoundary - Info.ScrollOffset; + for I := Info.FirstGridCell to Index - 1 do + Inc(Extent, Info.CellExtent(I) + Info.EffectiveSpacing(I)); + Delta := Extent; + for I := Index to Index + Span - 1 do + Inc(Delta, Info.CellExtent(I) + Info.EffectiveSpacing(I)); + if Delta > Info.ClientExtent then + begin + Delta := Min(Extent - Info.FixedBoundary, Delta + Info.ScrollOffset - Info.ClientExtent); + if Delta > 0 then + Result := True; + end else + Delta := 0; + end; + end; + +var + Horz, Vert: Boolean; + Span: TKGridCellSpan; +begin + DeltaHorz := 0; DeltaVert := 0; + Span := InternalGetCellSpan(ACol, ARow); + Horz := (FGridState <> gsRowMoving) and Axis(GetAxisInfoHorz([aiFixedParams]), ACol, Span.ColSpan, DeltaHorz); + Vert := (FGridState <> gsColMoving) and Axis(GetAxisInfoVert([aiFixedParams]), ARow, Span.RowSpan, DeltaVert); + Result := Horz or Vert; +end; + +procedure TKCustomGrid.ScrollTimerHandler(Sender: TObject); +var + DeltaHorz, DeltaVert, HitCol, HitRow, SelCol, SelRow: Integer; + MousePt: TPoint; +begin + MousePt := ScreenToClient(Mouse.CursorPos); + if MouseCapture and not Dragging and + PointToCell(MousePt, True, GridStateToInvisibleCells, HitCol, HitRow, + SelCol, SelRow) and ScrollNeeded(HitCol, HitRow, DeltaHorz, DeltaVert) then + begin + Scroll(cScrollDelta, cScrollDelta, DeltaHorz, DeltaVert, False); + if FGridState = gsSelecting then + begin + InternalFindBaseCell(SelCol, SelRow, SelCol, SelRow); + SelectionMove(SelCol, SelRow, ssExpand, [sfMustUpdate]) + end else + DragMove(HitCol, HitRow, MousePt); + end else + begin + FScrollTimer.Enabled := False; + UpdateEditor(Flag(cGF_EditorModeActive)); + end; +end; + +procedure TKCustomGrid.SelectAll; +begin + if goRangeSelect in Options then + // aki: + if (gxEditFixedRows in FOptionsEx) and (gxEditFixedCols in FOptionsEx) then + Selection := GridRect(0, 0, FColCount - 1, FRowCount - 1) + else if gxEditFixedRows in FOptionsEx then + Selection := GridRect(FFixedCols, 0, FColCount - 1, FRowCount - 1) + else if gxEditFixedCols in FOptionsEx then + Selection := GridRect(0, FFixedRows, FColCount - 1, FRowCount - 1) + else + Selection := GridRect(FFixedCols, FFixedRows, FColCount - 1, FRowCount - 1); +end; + +function TKCustomGrid.SelectCell(ACol, ARow: Integer): Boolean; +begin + // aki: + if (ColWidths[ACol] = 0) or (RowHeights[ARow] = 0) then + Result := False + else if (ARow < FFixedRows) and (not(gxEditFixedRows in FOptionsEx)) then + Result := False + else if not (gxEditFixedCols in FOptionsEx) and not (gxEditFixedRows in FOptionsEx) and (ACol < FFixedCols) then + Result := False + else + begin + Result := True; + if Assigned(FOnSelectCell) then + FOnSelectCell(Self, ACol, ARow, Result) + else if Assigned(FCells) then + InternalGetCell(ACol, ARow).SelectCell(ACol, ARow, Result); + end; +end; + +procedure TKCustomGrid.SelectCol(ACol: Integer); +begin + if goRangeSelect in Options then + // aki: + if gxEditFixedRows in FOptionsEx then + Selection := GridRect(ACol, 0, ACol, FRowCount - 1) + else + Selection := GridRect(ACol, FFixedRows, ACol, FRowCount - 1); +end; + +procedure TKCustomGrid.SelectCols(FirstCol, Count: Integer); +begin + if goRangeSelect in Options then + // aki: + if gxEditFixedRows in FOptionsEx then + Selection := GridRect(FirstCol, 0, FirstCol + Count, FRowCount - 1) + else + Selection := GridRect(FirstCol, FFixedRows, FirstCol + Count, FRowCount - 1); +end; + +procedure TKCustomGrid.SelectionChanged(NewSelection: TKGridRect; + Flags: TKGridSelectionFlags); +var + ICol, IRow: Integer; +begin + SelectionFix(NewSelection); + if FRangeSelectStyle = rsMS_Excel then + begin + ICol := NewSelection.Col2; + IRow := NewSelection.Row2; + end else + begin + ICol := NewSelection.Col1; + IRow := NewSelection.Row1; + end; + if (sfMustUpdate in Flags) and not GridRectEqual(FSelection, NewSelection) then + begin + InvalidateCurrentSelection; + FSelection := NewSelection; + if not (sfClampInView in Flags) or not ClampInView(ICol, IRow) then + InvalidateCurrentSelection; + end else + FSelection := NewSelection; + InvalidatePageSetup; + if not (sfNoMemPos in Flags) then + begin + FMemCol := ICol; + FMemRow := IRow; + end; + if sfMustUpdate in Flags then + UpdateEditor(Flag(cGF_EditorModeActive)); +end; + +function TKCustomGrid.SelectionExpand(ACol, ARow: Integer): Boolean; +begin + Result := True; + if Assigned(FOnSelectionExpand) then + FOnSelectionExpand(Self, ACol, ARow, Result) + else if Assigned(FCells) then + InternalGetCell(ACol, ARow).SelectionExpand(ACol, ARow, Result); +end; + +procedure TKCustomGrid.SelectionFix(var Sel: TKGridRect); +begin + //aki: + if (not (gxEditFixedCols in FOptionsEx) and (Sel.Row1 >= FFixedRows)) or (not (gxEditFixedRows in FOptionsEx) and (Sel.Row1 < FFixedRows)) then + begin + Sel.Col1 := MinMax(Sel.Col1, FFixedCols, FColCount - 1); + Sel.Col2 := MinMax(Sel.Col2, FFixedCols, FColCount - 1); + end else + begin + Sel.Col1 := MinMax(Sel.Col1, 0, FColCount - 1); + Sel.Col2 := MinMax(Sel.Col2, 0, FColCount - 1); + end; + if not (gxEditFixedRows in FOptionsEx) then + begin + Sel.Row1 := MinMax(Sel.Row1, FFixedRows, FRowCount - 1); + Sel.Row2 := MinMax(Sel.Row2, FFixedRows, FRowCount - 1); + end else + begin + Sel.Row1 := MinMax(Sel.Row1, 0, FRowCount - 1); + Sel.Row2 := MinMax(Sel.Row2, 0, FRowCount - 1); + end; + if not (goRangeSelect in FOptions) then + Sel.Cell2 := Sel.Cell1 +end; + +function TKCustomGrid.SelectionMove(ACol, ARow: Integer; + Stage: TKGridSelectionStage; + Flags: TKGridSelectionFlags): Boolean; +var + NewSelection: TKGridRect; +begin + Result := False; + if (Stage = ssExpand) and not (goRangeSelect in FOptions) then + Stage := ssInit; + case Stage of + ssInit: + begin + NewSelection := GridRect(ACol, ARow, ACol, ARow); + if not GridRectEqual(FSelection, NewSelection) and + ((sfDontCallSelectCell in Flags) or SelectCell(ACol, ARow)) then + Result := True; + end; + ssExpand: + begin + NewSelection := FSelection; + if FRangeSelectStyle = rsMS_Excel then + begin + NewSelection.Cell2 := GridPoint(ACol, ARow); + if not GridRectEqual(FSelection, NewSelection) and + ((sfDontCallSelectCell in Flags) or SelectionExpand(ACol, ARow)) then + Result := True; + end else + begin + NewSelection.Cell1 := GridPoint(ACol, ARow); + if not GridRectEqual(FSelection, NewSelection) and + ((sfDontCallSelectCell in Flags) or SelectCell(ACol, ARow)) then + Result := True; + end; + end; + end; + if Result then + SelectionChanged(NewSelection, Flags); + if not Result and GridRectEqual(NewSelection, FSelection) then + Result := True; +end; + +procedure TKCustomGrid.SelectionNormalize; +var + R: TKGridRect; +begin + R := Selection; + NormalizeGridRect(R); + Selection := R; +end; + +function TKCustomGrid.SelectionSet(const NewSelection: TKGridRect): Boolean; +begin + Result := False; + if not GridRectEqual(FSelection, NewSelection) then + begin + if ((FSelection.Col1 <> NewSelection.Col1) or (FSelection.Row1 <> NewSelection.Row1) + and SelectCell(NewSelection.Col1, NewSelection.Row1)) or + ((FSelection.Col2 <> NewSelection.Col2) or (FSelection.Row2 <> NewSelection.Row2) + and SelectionExpand(NewSelection.Col2, NewSelection.Row2)) then + Result := True; + end; + if Result then + SelectionChanged(NewSelection, [sfMustUpdate, sfClampInView]); +// if not Result and GridRectEqual(NewSelection, FSelection) then +// Result := True; +end; + +procedure TKCustomGrid.SelectRow(ARow: Integer); +begin + if goRangeSelect in Options then + Selection := GridRect(FFixedCols, ARow, FColCount - 1, ARow); +end; + +procedure TKCustomGrid.SelectRows(FirstRow, Count: Integer); +begin + if goRangeSelect in Options then + Selection := GridRect(FFixedCols, FirstRow, FColCount - 1, FirstRow + Count); +end; + +procedure TKCustomGrid.SetCell(ACol, ARow: Integer; Value: TKGridCell); +begin + if Assigned(FCells) and ColValid(ACol) and RowValid(ARow) then + InternalSetCell(ACol, ARow, Value); +end; + +procedure TKCustomGrid.SetCellPainterClass(Value: TKGridCellPainterClass); +begin + if Value <> FCellPainterClass then + begin + FCellPainterClass := Value; + FCellPainter.Free; + FCellPainter := FCellPainterClass.Create(Self); + end; +end; + +procedure TKCustomGrid.SetCells(ACol, ARow: Integer; const Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); +begin + if Assigned(FCells) and ColValid(ACol) and RowValid(ARow) then + InternalSetCells(ACol, ARow, Text); +end; + +procedure TKCustomGrid.SetCellSpan(ACol, ARow: Integer; Value: TKGridCellSpan); +var + I: Integer; +begin + if Assigned(FCells) and ColValid(ACol) and RowValid(ARow) then + begin + // cells cannot be merged across fixed area boundaries + if ACol >= FFixedCols then I := FColCount else I := FFixedCols; + Value.ColSpan := MinMax(Value.ColSpan, 1, I - ACol); + if ARow >= FFixedRows then I := FRowCount else I := FFixedRows; + Value.RowSpan := MinMax(Value.RowSpan, 1, I - ARow); + with InternalGetCell(ACol, ARow) do + if (ColSpan <> Value.ColSpan) or (RowSpan <> Value.RowSpan) then + begin + EditorMode := False; + FlagSet(cGF_GridUpdates); + try + InvalidateGridRect(InternalSetCellSpan(ACol, ARow, Value), False); + finally + FlagClear(cGF_GridUpdates); + end; + end; + end; +end; + +procedure TKCustomGrid.SetCol(Value: Integer); +begin + if ColSelectable(Value) and ((Value <> FSelection.Col1) or (FSelection.Col1 <> FSelection.Col2)) then + FocusCell(Value, Row); +end; + +procedure TKCustomGrid.SetColCount(Value: Integer); +begin + if Value < 1 then Value := 1; + InternalSetColCount(Value); +end; + +procedure TKCustomGrid.SetColWidths(Index: Integer; Value: Integer); +begin + if ColValid(Index) then + begin + if Value < InternalGetMinColWidth(Index) then + Value := 0 + else + Value := Min(Value, InternalGetMaxColWidth(Index)); + if Value <> FCols[Index].Extent then + begin + FlagSet(cGF_GridUpdates); + try + FCols[Index].Extent := Value; + finally + FlagClear(cGF_GridUpdates); + end; + UpdateAxes(True, Index, False, cAll, [afCallEvent, afCheckMinExtent]); + end; + end; +end; + +procedure TKCustomGrid.SetColors(Value: TKGridColors); +begin + FColors.Assign(Value); +end; + +{$IFDEF FPC} +procedure TKCustomGrid.SetCursor(Value: TCursor); +begin + FTmpCursor := Value; + if (FCursor <> crHSplit) and (FCursor <> crVSplit) and + (FCursor <> crHResize) and (FCursor <> crVResize) then + inherited; +end; +{$ENDIF} + +procedure TKCustomGrid.SetDefaultColWidth(Value: Integer); +begin + if Value <> FDefaultColWidth then + begin + FDefaultColWidth := Value; + DefaultColWidthChanged; + end; +end; + +procedure TKCustomGrid.SetDefaultDrawing(Value: Boolean); +begin + // does nothing +end; + +procedure TKCustomGrid.SetDefaultRowHeight(Value: Integer); +begin + if Value <> FDefaultRowHeight then + begin + FDefaultRowHeight := Value; + DefaultRowHeightChanged; + end; +end; + +procedure TKCustomGrid.SetDisabledDrawStyle(Value: TKGridDisabledDrawStyle); +begin + if Value <> FDisabledDrawStyle then + begin + FDisabledDrawStyle := Value; + if not Enabled then + Invalidate; + end; +end; + +procedure TKCustomGrid.SetDragStyle(Value: TKGridDragStyle); +begin + if Value <> FDragStyle then + begin + CancelMode; + FDragStyle := Value; + end; +end; + +procedure TKCustomGrid.SetEditorMode(Value: Boolean); +begin + if Value <> EditorMode then + UpdateEditor(Value); + FlagAssign(cGF_EditorModeActive, Value); +end; + +procedure TKCustomGrid.SetEditorTransparency(Value: TKGridEditorTransparency); +begin + if Value <> FEditorTransparency then + begin + FEditorTransparency := Value; + if EditorMode then + FEditor.Invalidate; + end; +end; + +procedure TKCustomGrid.SetFixedCols(Value: Integer); +begin + if (Value <> FFixedCols) and (FFixedCols >= 0) then + InternalSetFixedCols(Value); +end; + +procedure TKCustomGrid.SetFixedRows(Value: Integer); +begin + if (Value <> FFixedRows) and (FFixedRows >= 0) then + InternalSetFixedRows(Value); +end; + +{$IFDEF FPC} +procedure TKCustomGrid.SetFlat(Value: Boolean); +begin + if Value <> FFlat then + begin + FFlat := Value; + Invalidate; + end; +end; +{$ENDIF} + +procedure TKCustomGrid.SetGridLineWidth(Value: Integer); +begin + if FGridLineWidth <> Value then + begin + FGridLineWidth := Value; + UpdateAxes(FOptions * [goFixedHorzLine, goHorzLine] <> [], cAll, + FOptions * [goFixedVertLine, goVertLine] <> [], cAll, []); + end; +end; + +procedure TKCustomGrid.SetLeftCol(Value: Integer); +begin + if ColValid(Value) and (Value <> FTopLeft.Col) then + ScrollBy(Value - FTopLeft.Col, 0); +end; + +procedure TKCustomGrid.SetMinColWidth(Value: Integer); +var + I, Extent, MinColWidth: Integer; +begin + Value := Max(Value, cMinColWidthMin); + if Value <> FMinColWidth then + begin + FMinColWidth := Value; + if FMinColWidth > FDefaultColWidth then + begin + FDefaultColWidth := FMinColWidth; + DefaultColWidthChanged; + end else + begin + FlagSet(cGF_GridUpdates); + try + for I := 0 to FColCount - 1 do + begin + Extent := FCols[I].Extent; + MinColWidth := InternalGetMinColWidth(I); + if (Extent > 0) and (Extent < MinColWidth) then + FCols[I].Extent := MinColWidth; + end; + finally + FlagClear(cGF_GridUpdates); + end; + UpdateAxes(True, cAll, False, cAll, []); + end; + end; +end; + +procedure TKCustomGrid.SetMinRowHeight(Value: Integer); +var + I, Extent, MinRowHeight: Integer; +begin + Value := Max(Value, cMinRowHeightMin); + if Value <> FMinRowHeight then + begin + FMinRowHeight := Value; + if FMinRowHeight > FDefaultRowHeight then + begin + FDefaultRowHeight := FMinRowHeight; + DefaultRowHeightChanged; + end else + begin + FlagSet(cGF_GridUpdates); + try + for I := 0 to FRowCount - 1 do + begin + Extent := FRows[I].Extent; + MinRowHeight := InternalGetMinRowHeight(I); + if (Extent > 0) and (Extent < MinRowHeight) then + FRows[I].Extent := MinRowHeight; + end; + finally + FlagClear(cGF_GridUpdates); + end; + UpdateAxes(False, cAll, True, cAll, []); + end; + end; +end; + +procedure TKCustomGrid.SetMouseCellHintTime(const AValue: Cardinal); +begin + FMouseCellHintTime := MinMax(AValue, cMouseCellHintTimeMin, cMouseCellHintTimeMax); +end; + +function TKCustomGrid.SetMouseCursor(X, Y: Integer): Boolean; +var + ACursor: TCursor; + Index, Pos: Integer; + State: TKGridState; +begin +{$IFDEF FPC} + ACursor := FTmpCursor; +{$ELSE} + ACursor := Cursor; +{$ENDIF} + State := gsNormal; + Index := 0; Pos := 0; + PointToSizing(Point(X, Y), State, Index, Pos); + case State of + gsColSizing: + begin + FlagSet(cGF_DesignHitTest); + if (FCols[Index].Extent = 0) or (csDesigning in ComponentState) then + ACursor := crHSplit + else + ACursor := crHResize + end; + gsRowSizing: + begin + FlagSet(cGF_DesignHitTest); + if (FRows[Index].Extent = 0) or (csDesigning in ComponentState) then + ACursor := crVSplit + else + ACursor := crVResize; + end; + else + FlagClear(cGF_DesignHitTest); + end; +{$IFDEF FPC} + FCursor := ACursor; + SetTempCursor(ACursor); +{$ELSE} + Windows.SetCursor(Screen.Cursors[ACursor]); +{$ENDIF} + Result := True; +end; + +procedure TKCustomGrid.SetObjects(ACol, ARow: Integer; Value: TObject); +var + Cell, Tmp: TKGridCell; +begin + if Assigned(FCells) and ColValid(ACol) and RowValid(ARow) then + begin + FlagSet(cGF_GridUpdates); + try + Cell := InternalGetCell(ACol, ARow); + if not (Cell is TKGridObjectCell) then + begin + if FCellClass.InheritsFrom(TKGridObjectCell) then + Tmp := FCellClass.Create(Self) + else + Tmp := TKGridObjectCell.Create(Self); + Tmp.Assign(Cell); + Cell.Free; + FCells[ARow, ACol] := Tmp; + end; + TKGridObjectCell(FCells[ARow, ACol]).CellObject := Value; + finally + FlagClear(cGF_GridUpdates); + end; + InvalidateCell(ACol, ARow); + end +end; + +procedure TKCustomGrid.SetOptions(Value: TKGridOptions); +const + UpdatePaintSet = [goClippedCells, goDrawFocusSelected, goDoubleBufferedCells, + goFixedHorzLine, goFixedVertLine, goHeader, goHeaderAlignment, goHorzLine, + goIndicateSelection, goIndicateHiddenCells, goThemedCells, goThemes, goVertLine]; + UpdateScrollBarsSet = [goAlignLastCol, goAlignLastRow]; + UpdateSelectionSet = [goRangeSelect, goRowSelect]; + UpdateSortingSet = [goColSorting, goRowSorting]; +var + UpdateCols, UpdatePaint, UpdateRows, UpdateScrollBars, + UpdateSelection, UpdateSorting, UpdateThemes, UpdateThemedCells, + UpdateVirtualGrid, WasVirtual: Boolean; +begin + if FOptions <> Value then + begin + UpdateCols := ((Value * [goHorzLine, goFixedHorzLine] = []) xor + (FOptions * [goHorzLine, goFixedHorzLine] = [])) or + ((goIndicateHiddenCells in Value) <> (goIndicateHiddenCells in FOptions)); + UpdateRows := ((Value * [goVertLine, goFixedVertLine] = []) xor + (FOptions * [goVertLine, goFixedVertLine] = [])) or + ((goIndicateHiddenCells in Value) <> (goIndicateHiddenCells in FOptions)); + UpdatePaint := Value * UpdatePaintSet <> FOptions * UpdatePaintSet; + UpdateScrollBars := Value * UpdateScrollBarsSet <> FOptions * UpdateScrollBarsSet; + UpdateSelection := Value * UpdateSelectionSet <> FOptions * UpdateSelectionSet; + UpdateSorting := Value * UpdateSortingSet <> FOptions * UpdateSortingSet; + UpdateThemes := (goThemes in Value) <> (goThemes in FOptions); + UpdateThemedCells := (goThemedCells in Value) <> (goThemedCells in FOptions); + UpdateVirtualGrid := (goVirtualGrid in Value) <> (goVirtualGrid in FOptions); + WasVirtual := goVirtualGrid in FOptions; + FOptions := Value; + if UpdateSelection then + SelectionFix(FSelection); + if UpdateCols or UpdateRows then + UpdateAxes(UpdateCols, cAll, UpdateRows, cAll, []); + if UpdateScrollBars or UpdateThemes then + {$IFDEF FPC} + UpdateSize; + {$ELSE} + RecreateWnd; + {$ENDIF} + if UpdateSorting then + ClearSortMode; + if UpdateVirtualGrid then + begin + if InternalUpdateVirtualGrid then + ChangeDataSize(False, 0, 0, False, 0, 0) + else if WasVirtual then + Include(FOptions, goVirtualGrid) + else + Exclude(FOptions, goVirtualGrid); + end; + if UpdatePaint or UpdateSelection or UpdateVirtualGrid then + begin + Invalidate; + InvalidatePageSetup; + end; + if UpdateThemedCells then + Include(FOptions, goMouseOverCells); + if not (goEditing in FOptions) then + EditorMode := False; + end; +end; + +procedure TKCustomGrid.SetOptionsEx(Value: TKGridOptionsEx); +const + UpdatePaintSet = [gxFixedThemedCells]; +var + UpdatePaint: Boolean; +begin + if FOptionsEx <> Value then + begin + UpdatePaint := Value * UpdatePaintSet <> FOptionsEx * UpdatePaintSet; + FOptionsEx := Value; + if UpdatePaint then + Invalidate; + end; +end; + +procedure TKCustomGrid.SetRow(Value: Integer); +begin + if RowSelectable(Value) and ((Value <> FSelection.Row1) or (FSelection.Row1 <> FSelection.Row2)) then + FocusCell(Col, Value); +end; + +procedure TKCustomGrid.SetRowCount(Value: Integer); +begin + if Value < 1 then Value := 1; + InternalSetRowCount(Value); +end; + +procedure TKCustomGrid.SetRowHeights(Index: Integer; Value: Integer); +begin + if RowValid(Index) then + begin + if Value < InternalGetMinRowHeight(Index) then + Value := 0 + else + Value := Min(Value, InternalGetMaxRowHeight(Index)); + if Value <> FRows[Index].Extent then + begin + FlagSet(cGF_GridUpdates); + try + FRows[Index].Extent := Value; + finally + FlagClear(cGF_GridUpdates); + end; + UpdateAxes(False, cAll, True, Index, [afCallEvent, afCheckMinExtent]); + end; + end; +end; + +procedure TKCustomGrid.SetScrollBars(Value: TScrollStyle); +begin + if FScrollBars <> Value then + begin + FScrollBars := Value; + {$IFDEF FPC} + UpdateSize; + {$ELSE} + RecreateWnd; + {$ENDIF} + end; +end; + +procedure TKCustomGrid.SetScrollModeHorz(const Value: TKGridScrollMode); +begin + if Value <> FScrollModeHorz then + begin + FScrollModeHorz := Value; + UpdateScrollRange(True, False, True); + end; +end; + +procedure TKCustomGrid.SetScrollModeVert(const Value: TKGridScrollMode); +begin + if Value <> FScrollModeVert then + begin + FScrollModeVert := Value; + UpdateScrollRange(False, True, True); + end; +end; + +procedure TKCustomGrid.SetScrollSpeed(Value: Cardinal); +begin + Value := MinMax(Integer(Value), cScrollSpeedMin, cScrollSpeedMax); + if Value <> FScrollSpeed then + begin + FScrollSpeed := Value; + FScrollTimer.Enabled := False; + FScrollTimer.Interval := FScrollSpeed; + end; +end; + +procedure TKCustomGrid.SetSelection(const Value: TKGridRect); +var + G: TKGridRect; +begin + if GridRectSelectable(Value) and not GridRectEqual(Value, FSelection) then + begin + InternalFindBaseCell(Value.Col1, Value.Row1, G.Col1, G.Row1); + InternalFindBaseCell(Value.Col2, Value.Row2, G.Col2, G.Row2); + SelectionSet(G); + end; +end; + +procedure TKCustomGrid.SetSelections(Index: Integer; const Value: TKGridRect); +begin + if (Index >= 0) and (Index < SelectionCount) then + begin + //TODO! + end; +end; + +procedure TKCustomGrid.SetSizingStyle(Value: TKGridSizingStyle); +begin + if Value <> FSizingStyle then + begin + CancelMode; + FSizingStyle := Value; + end; +end; + +procedure TKCustomGrid.SetTabStops(Index: Integer; Value: Boolean); +begin + if ColValid(Index) and (FCols[Index] is TKGridCol) then + TKGridCol(FCols[Index]).TabStop := Value; +end; + +procedure TKCustomGrid.SetTopRow(Value: Integer); +begin + if RowValid(Value) and (Value <> FTopLeft.Row) then + ScrollBy(0, Value - FTopLeft.Row); +end; + +procedure TKCustomGrid.ShowCellHint; +begin + DefaultMouseCellHint(FHintCell.Col, FHintCell.Row, True); +end; + +procedure TKCustomGrid.SizeChanged(Change: TKGridSizeChange; + Index, Count: Integer); +begin + if Assigned(FOnSizeChanged) then + FOnSizeChanged(Self, Change, Index, Count); +end; + +procedure TKCustomGrid.SortCols(ByRow: Integer; SortMode: TKGridSortMode); +var + Sorted: Boolean; + OldSortMode: TKGridSortMode; +begin + if SortModeUnlocked and RowValid(ByRow) and (FRows[ByRow].SortMode <> SortMode) then + begin + OldSortMode := FRows[ByRow].SortMode; + ClearSortModeVert; + if FColCount > 1 then + begin + EditorMode := False; + Sorted := CustomSortCols(ByRow, SortMode); + if not Sorted and (SortMode <> smNone) then + begin + if OldSortMode <> smNone then + InternalFlip(FFixedCols, FColCount - 1, InternalExchangeCols) + else + InternalQuickSortNR(ByRow, FFixedCols, FColCount - 1, SortMode = smDown, + CompareCols, InternalExchangeCols); + end; + if Sorted or (SortMode <> smNone) then + begin + UpdateScrollRange(True, False, False); + UpdateCellSpan; + if not ClampInView(Col, Row) then + InvalidateCols(FFixedCols); + end; + if SortMode <> smNone then + begin + FlagSet(cGF_GridUpdates); + try + FRows[ByRow].SortMode := SortMode; + finally + FlagClear(cGF_GridUpdates); + end; + Row := ByRow; + end; + InvalidateGridRect(GridRect(0, ByRow, FFixedCols - 1, ByRow)); + end; + end; +end; + +function TKCustomGrid.SortModeUnlocked: Boolean; +begin + Result := FSortModeLock = 0; +end; + +procedure TKCustomGrid.SortRows(ByCol: Integer; SortMode: TKGridSortMode); +var + Sorted: Boolean; + OldSortMode: TKGridSortMode; +begin + if SortModeUnlocked and ColValid(ByCol) and (FCols[ByCol].SortMode <> SortMode) then + begin + OldSortMode := FCols[ByCol].SortMode; + ClearSortModeHorz; + if FRowCount > 1 then + begin + EditorMode := False; + Sorted := CustomSortRows(ByCol, SortMode); + if not Sorted and (SortMode <> smNone) then + begin + if OldSortMode <> smNone then + InternalFlip(FFixedRows, FRowCount - 1, InternalExchangeRows) + else + InternalQuickSortNR(ByCol, FFixedRows, FRowCount - 1, SortMode = smDown, + CompareRows, InternalExchangeRows); + end; + if Sorted or (SortMode <> smNone) then + begin + UpdateScrollRange(False, True, False); + UpdateCellSpan; + if not ClampInView(Col, Row) then + InvalidateRows(FFixedRows); + end; + if SortMode <> smNone then + begin + FlagSet(cGF_GridUpdates); + try + FCols[ByCol].SortMode := SortMode; + finally + FlagClear(cGF_GridUpdates); + end; + Col := ByCol; + end; + InvalidateGridRect(GridRect(ByCol, 0, ByCol, FFixedRows - 1)); + end; + end; +end; + +procedure TKCustomGrid.SuggestDrag(State: TKGridCaptureState); +var + R: TRect; +begin + if HandleAllocated and GetDragRect(GetAxisInfoBoth([aiGridBoundary]), R) then + begin + if State = csStart then + begin + InvalidateCell(FHitCell.Col, FHitCell.Row); + Update; + end; + InvalidateRect(Handle, @R, False); + end; +end; + +procedure TKCustomGrid.SuggestSizing(State: TKGridCaptureState); + + function Axis(const Info: TKGridAxisInfo; CellPt: Integer; AxisItems: TKGridAxisItems): Integer; + var + Tmp, MinExtent: Integer; + begin + Result := Info.CellExtent(FSizingIndex); + MinExtent := Info.MinCellExtent(FSizingIndex); + if goMouseCanHideCells in FOptions then + begin + if Result > 0 then + begin + if FSizingDest - CellPt > Max(MinExtent div 2, MinExtent - 5) then + Result := Max(FSizingDest - CellPt, MinExtent) + else + Result := 0; + end else + begin + Tmp := FSizingIndex; + while (Tmp > 0) and (Info.CellExtent(Tmp - 1) = 0) do + Dec(Tmp); + if Tmp <> FSizingIndex then + Inc(CellPt, Info.EffectiveSpacing(Tmp)); + if FSizingDest - CellPt >= MinExtent then + Result := FSizingDest - CellPt; + end; + end else + Result := Max(FSizingDest - CellPt, MinExtent); + end; + +var + R: TRect; + Info: TKGridAxisInfo; +begin + if HandleAllocated then + begin + case FGridState of + gsColSizing: + begin + case FSizingStyle of + ssLine, ssXORLine: + begin + Info := GetAxisInfoVert([aiGridBoundary]); + R := Rect(FSizingDest, 0, FSizingDest + 2, Info.GridBoundary); + InvalidateRect(Handle, @R, False); + end; + ssUpdate: + begin + if (State = csShow) and CellToPoint(FSizingIndex, 0, R.TopLeft) then + ColWidths[FSizingIndex] := Axis(GetAxisInfoHorz([]), R.Left, FCols); + end; + end; + end; + gsRowSizing: + begin + case FSizingStyle of + ssLine, ssXORLine: + begin + Info := GetAxisInfoHorz([aiGridBoundary]); + R := Rect(0, FSizingDest, Info.GridBoundary, FSizingDest + 2); + InvalidateRect(Handle, @R, False); + end; + ssUpdate: + begin + if (State = csShow) and CellToPoint(0, FSizingIndex, R.TopLeft) then + RowHeights[FSizingIndex] := Axis(GetAxisInfoVert([]), R.Top, FRows); + end; + end; + end; + end; + end; +end; + +procedure TKCustomGrid.TopLeftChanged; +begin + if Assigned(FOnTopLeftChanged) then + FOnTopLeftChanged(Self); +end; + +procedure TKCustomGrid.UnlockSortMode; +begin + if FSortModeLock > 0 then + Dec(FSortModeLock); +end; + +procedure TKCustomGrid.UnselectRange; +begin + Selection := GridRect(FSelection.Cell1); +end; + +procedure TKCustomGrid.UpdateAxes(Horz: Boolean; FirstCol: Integer; + Vert: Boolean; FirstRow: Integer; Flags: TKGridAxisUpdateFlags); + + procedure Axis1(Info: TKGridAxisInfo; AxisItems: TKGridAxisItems; + var FirstIndex: Integer); + var + I, AExtent: Integer; + begin + FlagSet(cGF_GridUpdates); + try + for I := 0 to Info.TotalCellCount - 1 do + begin + AExtent := Info.CellExtent(I); + if (AExtent > 0) and (AExtent < Info.MinCellExtent(I)) then + begin + AxisItems[I].Extent := 0; + FirstIndex := Min(FirstIndex, I); + end + else if AExtent > Info.MaxCellExtent(I) then + begin + AxisItems[I].Extent := Info.MaxCellExtent(I); + FirstIndex := Min(FirstIndex, I); + end; + end; + finally + FlagClear(cGF_GridUpdates); + end; + end; + + procedure Axis2(Info: TKGridAxisInfo; AxisItems: TKGridAxisItems; + var FirstIndex: Integer); + + function CalcGridExtent(FixedExtent: Integer): Integer; + var + I: Integer; + begin + Result := FixedExtent; + for I := Info.FixedCellCount to Info.TotalCellCount - 1 do + Inc(Result, Info.CellExtent(I) + Info.EffectiveSpacing(I)); + end; + + var + I, CellExtent, Delta, FixedExtent, GridExtent: Integer; + begin + FlagSet(cGF_GridUpdates); + try + FixedExtent := 0; + for I := 0 to Info.FixedCellCount - 1 do + Inc(FixedExtent, Info.CellExtent(I) + Info.EffectiveSpacing(I)); + GridExtent := CalcGridExtent(FixedExtent); + if GridExtent <> Info.ClientExtent then + begin + if GridExtent < Info.ClientExtent then + begin + // cells would occupy a smaller area than Info.ClientExtent + // try to enlarge the last cell if visible: + I := Info.TotalCellCount - 1; + while (I >= Info.FixedCellCount) and (GridExtent < Info.ClientExtent) do + begin + CellExtent := Info.CellExtent(I); + if CellExtent <> 0 then + begin + Delta := Info.ClientExtent - GridExtent; + AxisItems[I].Extent := CellExtent + Delta; + Inc(GridExtent, Delta); + FirstIndex := Min(FirstIndex, I); + end; + Dec(I); + end; + if I < Info.FixedCellCount then + begin + // apparently all cells are hidden. Try to unhide last cell + I := Info.TotalCellCount - 1; + AxisItems[I].Extent := Info.MinCellExtent(I); + GridExtent := CalcGridExtent(FixedExtent); + if GridExtent > Info.ClientExtent then + AxisItems[I].Extent := 0 //oops, does not fit, hide again, leave empty area + else + AxisItems[I].Extent := Info.CellExtent(I) + Info.ClientExtent - GridExtent; + end; + end else + begin + // cells would occupy a greater area than Info.ClientExtent + // try to decrease the extents of not fully visible cells + I := Info.TotalCellCount - 1; + while (I >= Info.FixedCellCount) and (GridExtent > Info.ClientExtent) do + begin + CellExtent := Info.CellExtent(I); + if CellExtent > Info.MinCellExtent(I) then + begin + Delta := Min(GridExtent - Info.ClientExtent, CellExtent - Info.MinCellExtent(I)); + AxisItems[I].Extent := CellExtent - Delta; + Dec(GridExtent, Delta); + FirstIndex := Min(FirstIndex, I); + end; + Dec(I); + end; + if GridExtent > Info.ClientExtent then + begin + // still everything not visible, hide some cells + I := Info.TotalCellCount - 1; + while (I >= Info.FixedCellCount) and (GridExtent > Info.ClientExtent) do + begin + CellExtent := Info.CellExtent(I); + if CellExtent > 0 then + begin + AxisItems[I].Extent := 0; + FirstIndex := Min(FirstIndex, I); + GridExtent := CalcGridExtent(FixedExtent); + end; + Dec(I); + end; + if (GridExtent < Info.ClientExtent) and (I >= Info.FixedCellCount) then + begin + // cells would occupy a smaller area than Info.ClientExtent - 2nd test + I := Info.TotalCellCount - 1; + while (I >= Info.FixedCellCount) and (GridExtent < Info.ClientExtent) do + begin + CellExtent := Info.CellExtent(I); + if CellExtent <> 0 then + begin + Delta := Info.ClientExtent - GridExtent; + AxisItems[I].Extent := CellExtent + Delta; + Inc(GridExtent, Delta); + FirstIndex := Min(FirstIndex, I); + end; + Dec(I); + end; + end; + end; + end; + end; + finally + FlagClear(cGF_GridUpdates); + end; + end; + +var + ColIndex, RowIndex: Integer; + Info: TKGridAxisInfo; +begin + if not UpdateUnlocked then Exit; + if Horz then + begin + Info := GetAxisInfoHorz([]); + if FirstCol >= 0 then ColIndex := FirstCol else ColIndex := FColCount; + if afCheckMinExtent in Flags then + Axis1(Info, FCols, ColIndex); + if (goAlignLastCol in FOptions) then + begin + if FTopLeft.Col <> FFixedCols then + begin + FTopLeft.Col := FFixedCols; + TopLeftChanged; + end; + Axis2(Info, FCols, ColIndex); + end; + end; + if Vert then + begin + Info := GetAxisInfoVert([]); + if FirstRow >= 0 then RowIndex := FirstRow else RowIndex := FRowCount; + if afCheckMinExtent in Flags then + Axis1(Info, FRows, RowIndex); + if (goAlignLastRow in FOptions) then + begin + if FTopLeft.Row <> FFixedRows then + begin + FTopLeft.Row := FFixedRows; + TopLeftChanged; + end; + Axis2(Info, FRows, RowIndex); + end; + end; + UpdateScrollRange(Horz, Vert, False); + UpdateEditor(Flag(cGF_EditorModeActive)); + if Horz then + begin + if ColIndex < FColCount then + ColWidthsChanged(ColIndex); + if FirstCol = cAll then + Invalidate + else if ColIndex < FColCount then + InvalidateCols(ColIndex); + end; + if Vert then + begin + if RowIndex < FRowCount then + RowHeightsChanged(RowIndex); + if FirstRow = cAll then + Invalidate + else if RowIndex < FRowCount then + InvalidateRows(RowIndex); + end; +end; + +procedure TKCustomGrid.UpdateCellSpan; + + function DoUpdate(FirstCol, FirstRow, LastCol, LastRow: Integer): Boolean; + var + I, J: Integer; + Span, RefSpan: TKGridCellSpan; + begin + Result := False; + RefSpan := MakeCellSpan(1, 1); + // don't make this too complicated, but maybe it is little bit slower: + // reset all negative spans + for I := FirstCol to LastCol - 1 do + for J := FirstRow to LastRow - 1 do + if FCells[J, I] <> nil then + begin + with FCells[J, I].Span do + if (ColSpan <= 0) or (RowSpan <= 0) then + FCells[J, I].Span := RefSpan; + end; + // create all spans + for I := FirstCol to LastCol - 1 do + for J := FirstRow to LastRow - 1 do + if FCells[J, I] <> nil then + begin + with FCells[J, I].Span do + if (ColSpan > 1) or (RowSpan > 1) then + begin + Result := True; + Span := MakeCellSpan(Min(ColSpan, LastCol - I), Min(RowSpan, LastRow - J)); + FCells[J, I].Span := RefSpan; + InternalSetCellSpan(I, J, Span); + end; + end; + end; + +begin + if Assigned(FCells) then + begin + FlagSet(cGF_GridUpdates); + try + // cells cannot be merged across fixed area boundaries + DoUpdate(0, 0, FFixedCols, FFixedRows); + DoUpdate(FFixedCols, 0, FColCount, FFixedRows); + DoUpdate(0, FFixedRows, FFixedCols, FRowCount); + if Flag(cGF_SelCellsMerged) then + if not DoUpdate(FFixedCols, FFixedRows, FColCount, FRowCount) then + FlagClear(cGF_SelCellsMerged); + finally + FlagClear(cGF_GridUpdates); + end; + end; +end; + +procedure TKCustomGrid.UpdateDesigner; +var + ParentForm: TCustomForm; +begin + if (csDesigning in ComponentState) and HandleAllocated and + not (csUpdating in ComponentState) then + begin + ParentForm := GetParentForm(Self); + if Assigned(ParentForm) and Assigned(ParentForm.Designer) then + ParentForm.Designer.Modified; + end; +end; + +procedure TKCustomGrid.UpdateEditor(Show: Boolean); + + procedure InternalEditorSetPos(R: TRect; CallResize: Boolean); + begin + // aki: + if ((FEditorCell.Col >= FTopLeft.Col) and ((FScrollOffset.X = 0) or (FEditorCell.Col > FTopLeft.Col)) or + (gxEditFixedCols in FOptionsEx) and (FEditorCell.Col < FFixedCols)) and + ((FEditorCell.Row >= FTopLeft.Row) and ((FScrollOffset.Y = 0) or (FEditorCell.Row > FTopLeft.Row)) or + (gxEditFixedRows in FOptionsEx) and (FEditorCell.Row < FFixedRows)) then + begin + if CallResize then + EditorResize(FEditor, FEditorCell.Col, FEditorCell.Row, R); + with R do + begin + FEditor.Constraints.MaxWidth := Right - Left + 1; + FEditor.Constraints.MaxHeight := Bottom - Top + 1; + FEditor.Height := Bottom - Top; + FEditor.Width := Right - Left; + if gxEditorVCenter in FOptionsEx then + Inc(Top, (Bottom - Top - FEditor.Height) div 2); + if gxEditorHCenter in FOptionsEx then + Inc(Left, (Right - Left - FEditor.Width) div 2); + FEditor.SetBounds(Left, Top, FEditor.Width, FEditor.Height); + end; + end else + begin + // hide the editor in some way + FEditor.Left := - 10 - FEditor.Width; + FEditor.Top := - 10 - FEditor.Height; + end; + end; + + procedure InternalEditorMove; + var + R: TRect; + begin + if (FEditor <> nil) and CellRect(FEditorCell.Col, FEditorCell.Row, R) then + begin + if not EqualRect(FEditorRect, R) then with R do + begin + FEditorRect := R; + InternalEditorSetPos(R, True); + SetControlClipRect(FEditor, R); + end; + end; + end; + + procedure InternalEditorCreate; + var + R: TRect; + PropInfo: PPropInfo; + P: TPoint; + ACell: TKGridCell; + begin + if (FEditor = nil) and HandleAllocated and Enabled and Visible then + begin + if CellRect(Col, Row, R) and SelectCell(Col, Row) then + begin + FEditorCell.Col := Col; + FEditorCell.Row := Row; + FEditor := EditorCreate(FEditorCell.Col, FEditorCell.Row); + if FEditor <> nil then + begin + if Assigned(FCells) then + begin + ACell := Cell[FEditorCell.Col, FEditorCell.Row]; + if FEditedCell = nil then FEditedCell := TKGridCellClass(ACell.ClassType).Create(nil); + FEditedCell.Assign(ACell); + end; + FThroughClick := False; + FEditorRect := R; + TabStop := False; + FEditor.Visible := False; + FEditor.Align := alNone; + FEditor.Constraints.MinWidth := 0; + FEditor.Constraints.MinHeight := 0; + PropInfo := GetPropInfo(FEditor, 'AutoSize'); + if PropInfo <> nil then + SetOrdProp(FEditor, PropInfo, Integer(False)); + // I hope no other steps to delimit inplace editor's size + // some controls as TComboBox on Win cannot be arbitrary resized :-( + FEditor.ControlStyle := FEditor.ControlStyle - [csAcceptsControls, csFramed, csFixedWidth, csFixedHeight] {$IFDEF COMPILER7_UP} - [csParentBackground] {$ENDIF}; + FEditor.TabStop := True; + InternalEditorSetPos(R, True); // call this here too to be compatible with all LCL widget sets + FEditor.Parent := Self; + FEditor.HandleNeeded; + InternalEditorSetPos(R, True); + SetControlClipRect(FEditor, R); + EditorDataFromGrid(FEditor, FEditorCell.Col, FEditorCell.Row); + FEditor.Visible := True; // Remark: don't set DoubleBuffered because not all editors support it! + EditorSelect(FEditor, FEditorCell.Col, FEditorCell.Row, + not (goNoSelEditText in FOptions), Flag(cGF_CaretToLeft), Flag(cGF_SelectedByMouse)); + FlagClear(cGF_CaretToLeft); + SafeSetFocus; + if FThroughClick then + begin + P := FEditor.ScreenToClient(Mouse.CursorPos); + PostMessage(FEditor.Handle, LM_LBUTTONDOWN, 1, MakeLong(P.X, P.Y)); + MouseCapture := False; + FlagSet(cGF_ThroughClick); + FThroughClick := False; + end; + InvalidateCurrentSelection; + FEditorWindowProc := FEditor.WindowProc; + FEditor.WindowProc := EditorWindowProc; + end; + end; + end; + end; + + procedure InternalEditorDestroy; + var + Form: TCustomForm; + begin + if FEditor <> nil then + begin + FEditor.WindowProc := FEditorWindowProc; + Form := GetParentForm(Self); + if Assigned(Form) and (csDestroying in Form.ComponentState) then + Form := nil; + if FEditor.HandleAllocated then + EditorDataToGrid(FEditor, FEditorCell.Col, FEditorCell.Row); + TabStop := True; + if Assigned(Form) and (Form.ActiveControl = FEditor) then + Form.ActiveControl := Self; + FEditor.Visible := False; + FEditor.Parent := nil; + EditorDestroy(FEditor, FEditorCell.Col, FEditorCell.Row); + FreeAndNil(FEditor); + if Assigned(FCells) then + if CompareCellInstances(FEditedCell, InternalGetCell(FEditorCell.Col, FEditorCell.Row)) <> 0 then + Changed; + FEditorCell := GridPoint(-1, -1); + if Assigned(Form) and (Form.ActiveControl = nil) then + Form.ActiveControl := Self; + InvalidateCurrentSelection; + end; + end; + +var + PosChanged: Boolean; +begin + if not Flag(cGF_EditorUpdating) then + begin + FlagSet(cGF_EditorUpdating); + try + if (goEditing in FOptions) and Show and (InternalGetColWidths(Col) > 0) and (InternalGetRowHeights(Row) > 0) then + begin + PosChanged := (FEditorCell.Col <> Col) or (FEditorCell.Row <> Row); + if (FEditor = nil) or PosChanged then + begin + InternalEditorDestroy; + InternalEditorCreate; + end else + InternalEditorMove; + end else + InternalEditorDestroy; + finally + FlagClear(cGF_EditorUpdating); + end; + end; +end; + +procedure TKCustomGrid.UpdateScrollRange(Horz, Vert, UpdateNeeded: Boolean); + + function Axis(Code: Cardinal; HasScrollBar: Boolean; ScrollMode: TKGridScrollMode; + Info: TKGridAxisInfo; out FirstGridCell, FirstGridCellExtent, ScrollPos: Integer; + var ScrollOffset: Integer): Boolean; + var + I, CellExtent, MaxExtent, PageExtent, ScrollExtent: Integer; + CheckFirstGridCell: Boolean; + SI: TScrollInfo; + begin + Result := False; + CheckFirstGridCell := True; + ScrollExtent := 0; + PageExtent := 0; + MaxExtent := Info.ClientExtent - Info.FixedBoundary; + I := Info.TotalCellCount - 1; + FirstGridCellExtent := I; + while I >= Info.FixedCellCount do + begin + CellExtent := Info.CellExtent(I); + Inc(ScrollExtent, CellExtent + Info.EffectiveSpacing(I)); + if CheckFirstGridCell then + begin + if (ScrollExtent <= MaxExtent) then + begin + PageExtent := ScrollExtent; + FirstGridCellExtent := I; + if (Info.FirstGridCell > I) or (Info.FirstGridCell = I) and (ScrollOffset <> 0) then + begin + FirstGridCell := I; + Result := True; + end; + end else + begin + if PageExtent = 0 then + PageExtent := ScrollExtent; + CheckFirstGridCell := False; + end; + end; + if I = FirstGridCell then + ScrollPos := ScrollExtent; + Dec(I); + end; + ScrollPos := ScrollExtent - ScrollPos; + if Result or ((ScrollMode = smCell) or not HasScrollBar) and (ScrollOffset <> 0) then + begin + ScrollOffset := 0; + Result := True; + end; + if HandleAllocated then + if HasScrollBar then + begin + FillChar(SI, SizeOf(TScrollInfo), 0); + SI.cbSize := SizeOf(TScrollInfo); + SI.fMask := SIF_RANGE or SIF_PAGE or SIF_POS {$IFDEF UNIX}or SIF_UPDATEPOLICY{$ENDIF}; + SI.nMin := 0; + SI.nMax := ScrollExtent {$IFNDEF FPC}- 1{$ENDIF}; + SI.nPos := ScrollPos + ScrollOffset; + SI.nPage := PageExtent; + {$IFDEF UNIX} + SI.ntrackPos := SB_POLICY_CONTINUOUS; + {$ENDIF} + SetScrollInfo(Handle, Code, SI, True); + ShowScrollBar(Handle, Code, PageExtent < ScrollExtent); + end else + ShowScrollBar(Handle, Code, False); + end; + +var + UpdateHorz, UpdateVert: Boolean; +begin + if not UpdateUnlocked then Exit; + UpdateHorz := Horz and Axis(SB_HORZ, HasHorzScrollBar, FScrollModeHorz, + GetAxisInfoHorz([aiFixedParams]), FTopLeft.Col, FTopLeftExtent.Col, FScrollPos.X, FScrollOffset.X); + UpdateVert := Vert and Axis(SB_VERT, HasVertScrollBar, FScrollModeVert, + GetAxisInfoVert([aiFixedParams]), FTopLeft.Row, FTopLeftExtent.Row, FScrollPos.Y, FScrollOffset.Y); + if UpdateNeeded or UpdateHorz then + InvalidateCols(FFixedCols); + if UpdateNeeded or UpdateVert then + InvalidateRows(FFixedRows); + if UpdateNeeded or UpdateHorz or UpdateVert then + begin + UpdateEditor(Flag(cGF_EditorModeActive)); + if UpdateHorz or UpdateVert then + TopLeftChanged; + if FOptions * [goRowSelect, goRangeSelect] <> [] then + InvalidateCurrentSelection; + end; + InvalidatePageSetup; +end; + +procedure TKCustomGrid.UpdateSize; +begin + inherited; + UpdateAxes(True, FColCount, True, FRowCount, [afCheckMinExtent]); +end; + +procedure TKCustomGrid.UpdateSortMode(ACol, ARow: Integer); +var + Index: Integer; +begin + LockSortMode; + try + if FCols[ACol].SortMode <> smNone then + begin + Index := InternalInsertIfCellModifiedNR(ACol, ARow, FFixedRows, FRowCount - 1, FCols[ACol].SortMode = smUp, CompareRows); + if Index <> ARow then + begin + MoveRow(ARow, Index); + ClampInView(ACol, Index); + end; + end; + if FRows[ARow].SortMode <> smNone then + begin + Index := InternalInsertIfCellModifiedNR(ARow, ACol, FFixedCols, FColCount - 1, FRows[ARow].SortMode = smUp, CompareCols); + if Index <> ACol then + begin + MoveCol(ACol, Index); + ClampInView(Index, ARow); + end; + end; + finally + UnlockSortMode; + end; +end; + +procedure TKCustomGrid.WMChar(var Msg: {$IFDEF FPC}TLMChar{$ELSE}TWMChar{$ENDIF}); +begin + if (goEditing in Options) and CharInSetEx(Char(Msg.CharCode), [^H, #32..#255]) then + begin + EditorMode := True; + if EditorMode then + PostMessage(FEditor.Handle, LM_CHAR, Word(Msg.CharCode), 0); + Msg.Result := 1; + end else + inherited; +end; + +procedure TKCustomGrid.WMEraseBkGnd(var Msg: TLMEraseBkGnd); +begin + if Flag(cGF_EditorUpdating) or not (goEraseBackground in FOptions) then + Msg.Result := 1 + else + inherited; +end; + +procedure TKCustomGrid.WMGetDlgCode(var Msg: TLMNoParams); +begin + Msg.Result := DLGC_WANTARROWS; + if goTabs in FOptions then Msg.Result := Msg.Result or DLGC_WANTTAB; + if goEditing in FOptions then Msg.Result := Msg.Result or DLGC_WANTCHARS; +end; + +procedure TKCustomGrid.WMHScroll(var Msg: TLMHScroll); +begin + if not EditorMode or (Msg.ScrollBar <> FEditor.Handle) then + begin + SafeSetFocus; + Scroll(Msg.ScrollCode, cScrollNoAction, Msg.Pos, 0, True); + end else + inherited; +end; + +procedure TKCustomGrid.WMKillFocus(var Msg: TLMKillFocus); +begin + inherited; + // focus moves to another control including inplace editor + if not Flag(cGF_EditorUpdating) then + InvalidateCurrentSelection; +end; + +procedure TKCustomGrid.WMSetFocus(var Msg: TLMSetFocus); +begin + // focus moves to the grid - post message + if not Flag(cGF_EditorUpdating) then + PostLateUpdate(FillMessage(LM_SETFOCUS, 0, 0), True); +end; + +procedure TKCustomGrid.WMVScroll(var Msg: TLMVScroll); +begin + if not EditorMode or (Msg.ScrollBar <> FEditor.Handle) then + begin + SafeSetFocus; + Scroll(cScrollNoAction, Msg.ScrollCode, 0, Msg.Pos, True); + end else + inherited; +end; + +{$IFNDEF FPC} +procedure TKCustomGrid.WndProc(var Msg: TMessage); + + procedure PaintCellBackground(ACanvas: TCanvas; R: TRect); + var + TmpBlockRect: TRect; + begin + R := Rect(0, 0, R.Right - R.Left, R.Bottom - R.Top); + TmpBlockRect := SelectionRect; + OffsetRect(TmpBlockRect, -R.Left, -R.Top); + InternalPaintCell(Col, Row, GetDrawState(Col, Row, HasFocus), + R, TmpBlockRect, ACanvas, False, False); + end; + +var + R: TRect; + SaveIndex: Integer; + ACanvas: TCanvas; +begin + case Msg.Msg of + WM_CTLCOLORBTN..WM_CTLCOLORSTATIC: + begin + if EditorMode and EditorIsTransparent and + CellRect(Col, Row, R) then + begin + if Themes then + begin + ACanvas := TCanvas.Create; + SaveIndex := SaveDC(Msg.WParam); + try + ACanvas.Handle := Msg.WParam; + PaintCellBackground(ACanvas, R); + finally + RestoreDC(Msg.WParam, SaveIndex); + ACanvas.Free; + end; + Msg.Result := GetStockObject(NULL_BRUSH); + end else + begin + PaintCellBackground(FTmpBitmap.Canvas, R); + SetTextColor(Msg.WParam, ColorToRGB(TCheckBox(FEditor).Font.Color)); + SetBkColor(Msg.WParam, ColorToRGB(FTmpBitmap.Canvas.Brush.Color)); + Msg.Result := FTmpBitmap.Canvas.Brush.Handle; + end; + end else + inherited; + end; + else + inherited; + end +end; +{$ENDIF} + +procedure TKCustomGrid.WriteColWidths(Writer: TWriter); +var + I: Integer; +begin + with Writer do + begin + WriteListBegin; + for I := 0 to FColCount - 1 do WriteInteger(ColWidths[I]); + WriteListEnd; + end; +end; + +procedure TKCustomGrid.WriteRowHeights(Writer: TWriter); +var + I: Integer; +begin + with Writer do + begin + WriteListBegin; + for I := 0 to FRowCount - 1 do WriteInteger(RowHeights[I]); + WriteListEnd; + end; +end; + +{$IFDEF FPC} +initialization + {$i kgrids.lrs} +{$ELSE} + {$R kgrids.res} +{$ENDIF} +end. diff --git a/components/kcontrols/source/kgrids.res b/components/kcontrols/source/kgrids.res new file mode 100755 index 0000000000000000000000000000000000000000..bc30efc037ef9e228a9dc0886b6c5c69c44677f9 GIT binary patch literal 3084 zcmcguO-L0{6h7n6^QUm$A|Yy#LSPF^Qwxf~c|I+FN@1)Q2_kMmVVPr&nCH`KU9 z$I;$qtA#|H5jx3rL~l`Ffp0{JW>HG}9bAoQq0F6I9JzJURa|X%2!C!mXPsLfSdyR4 z?XVl=EzWZziPLZ7BmN$_h?BhO1$gd!B%9_;XZ~FFGEWz|oo?{}J>)dep9r1edb-1R zi58L1w+NNuh%#ihiPFkcLVxXs2`(?Q}g< z!-UG_|7&;zuVmq^ve#BKR(1^EUmvbE&_&n5a?HQJqz5s*)(@aAuIFjlkf)(`28?OA zltHF=#Z$%DR|5HpXU>{j^Pz@Y=2~*`6|dxF30E&wbMi})(`#uSogdBSE1vPnU~|Fb z_)46|*T#9~=L}D+PjT<-UN2wXL)yw?tFa7M-*Zdhd5s&E8+hdF2v2WJ>v->TZ=I`_ zsyO*M$rC>&Lb>G&YRA{Kt-Vr3{732BZlJvrXYv9`Lgnr!Tz;cH8J z5Yua`4E0jDUR$;9bK&fx$rh@&(VY$>d_5;Sja4y&Jjg?U8y^;{V$z)Er@#x~84wby zV#aukp8#)w@4zAu5UXOkxQlNC_kl^^G4Kc&2krq`m_x{vz%wb5w66@J?SIB0;ZCAYuK6pU&ol&Ovhb4v{t&z V=%jfPBV6etz;>orVh?)d(O)B6bZr0t literal 0 HcmV?d00001 diff --git a/components/kcontrols/source/khexeditor.pas b/components/kcontrols/source/khexeditor.pas new file mode 100755 index 000000000..771558e66 --- /dev/null +++ b/components/kcontrols/source/khexeditor.pas @@ -0,0 +1,5118 @@ +{ @abstract(This unit contains the TKHexEditor component and all supporting classes) + @author(Tomas Krysl (tk@tkweb.eu)) + @created(12 Oct 2005) + @lastmod(20 Jun 2010) + + This unit provides a powerfull hexadecimal editor component @link(TKHexEditor) + with following major features: +
    +
  • advanced editing capabilities
  • +
  • advanced rendering styles
  • +
  • clipboard operations
  • +
  • virtually unlimited undo/redo operations
  • +
  • key mapping functionality
  • +
  • fast search/replace function
  • +
  • print/preview function
  • +
+ + Copyright © 2006 Tomas Krysl (tk@@tkweb.eu)

+ + License:
+ This code is distributed as a freeware. You are free to use it as part + of your application for any purpose including freeware, commercial and + shareware applications. The origin of this source code must not be + misrepresented; you must not claim your authorship. You may modify this code + solely for your own purpose. Please feel free to contact the author if you + think your changes might be useful for other users. You may distribute only + the original package. The author accepts no liability for any damage + that may result from using this code. } + +unit KHexEditor; + +{$include kcontrols.inc} +{$WEAKPACKAGEUNIT ON} + +interface + +uses +{$IFDEF FPC} + LCLType, LCLIntf, LMessages, LCLProc, LResources, +{$ELSE} + Windows, Messages, +{$ENDIF} + SysUtils, Classes, Graphics, Controls, + ExtCtrls, StdCtrls, Forms, KFunctions, KControls, KEditCommon; + +resourcestring + { @exclude } + sAddressText = 'Address area text'; + { @exclude } + sAddressBkGnd = 'Address area background'; + { @exclude } + sBkGnd = 'Editor background'; + { @exclude } + sDigitTextEven = 'Digit area even column'; + { @exclude } + sDigitTextOdd = 'Digit area odd column'; + { @exclude } + sDigitBkgnd = 'Digit area background'; + { @exclude } + sHorzLines = 'Horizontal lines'; + { @exclude } + sInactiveCaretBkGnd = 'Inactive caret background'; + { @exclude } + sInactiveCaretSelBkGnd = 'Selected inactive caret background'; + { @exclude } + sInactiveCaretSelText = 'Selected inactive caret text'; + { @exclude } + sInactiveCaretText = 'Inactive caret text'; + { @exclude } + sLinesHighLight = 'Lines highlight'; + { @exclude } + sSelBkGnd = 'Selection background'; + { @exclude } + sSelBkGndFocused = 'Focused selection background'; + { @exclude } + sSelText = 'Selection text'; + { @exclude } + sSelTextFocused = 'Focused selection text'; + { @exclude } + sSeparators = 'Area separating lines'; + { @exclude } + sTextText = 'Text area text'; + { @exclude } + sTextBkGnd = 'Text area background'; + { @exclude } + sVertLines = 'Vertical lines'; + +type + { Declares possible values for the @link(TKCustomHexEditor.AddressMode) property } + TKHexEditorAddressMode = ( + { Address will be shown in decimal format } + eamDec, + { Address will be shown in hexadecimal format } + eamHex + ); + + { Declares possible values e.g. for the @link(TKCustomHexEditor.EditArea) property } + TKHexEditorArea = ( + { No area is selected, e.g. when clicked outside of visible text } + eaNone, + { Address area selected/used } + eaAddress, + { Digits area selected/used } + eaDigits, + { Text area selected/used } + eaText + ); + + { @abstract(Contains dimensions of all areas in characters) +
    + Members: +
  • Address - address area width
  • +
  • AddressOut - address area leadout
  • +
  • Digits - digits area width
  • +
  • DigitsIn - digits area leadin
  • +
  • DigitsOut - digits area leadout
  • +
  • Text - text area width
  • +
  • TextIn - text area leadin
  • +
  • TotalHorz - total width of all defined areas
  • +
  • TotalVert - total number of lines
  • +
+ } + TKHexEditorAreaDimensions = record + Address, + AddressOut, + Digits, + DigitsIn, + DigitsOut, + Text, + TextIn, + TotalHorz, + TotalVert: Integer; + end; + + { Declares possible indexes e.g. for the @link(TKHexEditorColors.Color) property. } + TKHexEditorColorIndex = Integer; + + { @abstract(Declares @link(TKHexEditorColors) color item description) +
    + Members: +
  • Def - default color value
  • +
  • Name - color name (can be localized)
  • +
+ } + TKHexEditorColorSpec = record + Def: TColor; + Name: string; + end; + + { Declares possible values for the @link(TKCustomHexEditor.DisabledDrawStyle) property } + TKHexEditorDisabledDrawStyle = ( + { The lines will be painted with brighter colors when editor is disabled } + eddBright, + { The lines will be painted with gray text and white background when editor is disabled } + eddGrayed, + { The lines will be painted normally when editor is disabled } + eddNormal + ); + + { Declares drawing styles - possible values for the @link(TKCustomHexEditor.DrawStyles) property } + TKHexEditorDrawStyle = ( + { Show adress area } + edAddress, + { Show digits area } + edDigits, + { Show text area } + edText, + { Show horizontal leading lines } + edHorzLines, + { Show caret position when editor is inactive (has no input focus) } + edInactiveCaret, + { Show vertical area separating lines } + edSeparators, + { Show vertical leading lines (digits area only) } + edVertLines, + { @link(TKHexEditorColors.BkGnd) is used for all areas if included } + edSingleBkGnd + ); + + { Drawing styles can be arbitrary combined } + TKHexEditorDrawStyles = set of TKHexEditorDrawStyle; + + { @abstract(Declares the paint data structure for the @link(TKCustomHexEditor.PaintLines) method) +
    + Members: +
  • Canvas - destination canvas
  • +
  • PainRect - bounding rectangle for painted lines (no clipping necessary, + this is performed by window/page client area)
  • +
  • TopLine - first line painted (vertical scroll offset)
  • +
  • BottomLine - last line painted
  • +
  • LeftChar - first character painted (horizontal scroll offset)
  • +
  • CharWidth - character width in pixels for supplied canvas
  • +
  • CharHeight - character height in pixels for supplied canvas
  • +
  • CharSpacing - inter-character spacing in pixels for supplied canvas
  • +
  • Printing - determines whether normal painting or page printing should be performed
  • +
  • PaintAll - when Printing is True, specifies whether all data or selection only + should be painted, this applies only to the first and/or last painted line
  • +
  • PaintColors - when Printing is True, specifies whether to paint with colors or grayscale
  • +
  • PaintSelection - when Printing is True, specifies whether to indicate the selection
  • +
+ } + TKHexEditorPaintData = record + Canvas: TCanvas; + PaintRect: TRect; + TopLine, + BottomLine, + LeftChar, + CharWidth, + CharHeight, + CharSpacing: Integer; + Printing, + PaintAll, + PaintColors, + PaintSelection, + CaretShown: Boolean; + end; + + { @abstract(Declares the selection structure) +
    + Members: +
  • Index - byte index
  • +
  • Digit - digit index
  • +
+ } + TKHexEditorSelection = record + Index: Integer; + Digit: Integer; + end; + + { @abstract(Declares the structure for the @link(TKCustomHexEditor.SelText) property) +
    + Members: +
  • AsBinaryRaw - selected data as binary characters not mapped
  • +
  • AsBinaryMapped - selected data as binary characters mapped
  • +
  • AsDigits - selected data as hexadecimal digits
  • +
  • AsDigitsByteAligned - selected data as hexadecimal digits + without regarding cross-byte selections
  • +
+ } + TKHexEditorSelText = record + AsBinaryRaw, + AsBinaryMapped, + AsDigits, + AsDigitsByteAligned: AnsiString; + end; + + { Declares hex editor states - possible values for the @link(TKCustomHexEditor.States) property + (protected) } + TKHexEditorState = ( + { Caret is visible } + elCaretVisible, + { Caret is being updated } + elCaretUpdate, + { Ignore following WM_CHAR message } + elIgnoreNextChar, + { Buffer modified } + elModified, + { Mouse captured } + elMouseCapture, + { Overwrite mode active } + elOverwrite, + { Read only editor } + elReadOnly + ); + + { Hex editor states can be arbitrary combined } + TKHexEditorStates = set of TKHexEditorState; + + { @abstract(Declares the color description structure returned by @link(TKHexEditorColors.ColorData) property) +
    + Members: +
  • Index - color index
  • +
  • Color - current color value
  • +
  • Default - default color value
  • +
  • Name - color name
  • +
+ } + TKHexEditorColorData = record + Index: TKHexEditorColorIndex; + Color: TColor; + Default: TColor; + Name: string; + end; + + { Declares possible values for the @link(TKHexEditorColors.ColorScheme) property } + TKHexEditorColorScheme = ( + { GetColor returns normal color currently defined for each item } + ecsNormal, + { GetColor returns gray for text and line colors and white for background colors } + ecsGrayed, + { GetColor returns brighter version of normal color } + ecsBright, + { GetColor returns grayscaled color versions } + ecsGrayScale + ); + +const + { Minimum for the @link(TKCustomHexEditor.AddressSize) property } + cAddressSizeMin = 2; + { Maximum for the @link(TKCustomHexEditor.AddressSize) property } + cAddressSizeMax = 10; + { Default value for the @link(TKCustomHexEditor.AddressSize) property } + cAddressSizeDef = 8; + + { Minimum for the @link(TKCustomHexEditor.AreaSpacing) property } + cAreaSpacingMin = 1; + { Maximum for the @link(TKCustomHexEditor.AreaSpacing) property } + cAreaSpacingMax = 20; + { Default value for the @link(TKCustomHexEditor.AreaSpacing) property } + cAreaSpacingDef = 1; + + { Minimum for the @link(TKCustomHexEditor.CharSpacing) property } + cCharSpacingMin = 0; + { Maximum for the @link(TKCustomHexEditor.CharSpacing) property } + cCharSpacingMax = 100; + { Default value for the @link(TKCustomHexEditor.CharSpacing) property } + cCharSpacingDef = 0; + + { Minimum for the @link(TKCustomHexEditor.DigitGrouping) property } + cDigitGroupingMin = 1; + { Maximum for the @link(TKCustomHexEditor.DigitGrouping) property } + cDigitGroupingMax = 8; + { Default value for the @link(TKCustomHexEditor.DigitGrouping) property } + cDigitGroupingDef = 2; + + { Minimum for the @link(TKCustomHexEditor.LineHeightPercent) property } + cLineHeightPercentMin = 10; + { Maximum for the @link(TKCustomHexEditor.LineHeightPercent) property } + cLineHeightPercentMax = 1000; + { Default value for the @link(TKCustomHexEditor.LineHeightPercent) property } + cLineHeightPercentDef = 130; + + { Minimum for the @link(TKCustomHexEditor.UndoLimit) property } + cUndoLimitMin = 100; + { Maximum for the @link(TKCustomHexEditor.UndoLimit) property } + cUndoLimitMax = 10000; + { Default value for the @link(TKCustomHexEditor.UndoLimit) property } + cUndoLimitDef = 1000; + + { Minimum for the @link(TKCustomHexEditor.LineSize) property } + cLineSizeMin = 1; + { Maximum for the @link(TKCustomHexEditor.LineSize) property } + cLineSizeMax = 128; + { Default value for the @link(TKCustomHexEditor.LineSize) property } + cLineSizeDef = 16; + + { Minimum for the @link(TKCustomHexEditor.ScrollSpeed) property } + cScrollSpeedMin = 50; + { Maximum for the @link(TKCustomHexEditor.ScrollSpeed) property } + cScrollSpeedMax = 1000; + { Default value for the @link(TKCustomHexEditor.ScrollSpeed) property } + cScrollSpeedDef = 100; + + { Minimum for the @link(TKHexEditor.Font).Size property } + cFontSizeMin = 8; + { Maximum for the @link(TKHexEditor.Font).Size property } + cFontSizeMax = 100; + { Default value for the @link(TKHexEditor.Font).Size property } + cFontSizeDef = 11; + + { Default value for the @link(TKHexEditorColors.AddressText) color property } + cAddressTextDef = clWindowText; + { Default value for the @link(TKHexEditorColors.AddressBkGnd) color property } + cAddressBkgndDef = clWindow; + { Default value for the @link(TKHexEditorColors.BkGnd) color property } + cBkGndDef = clWindow; + { Default value for the @link(TKHexEditorColors.DigitTextEven) color property } + cDigitTextEvenDef = clMaroon; + { Default value for the @link(TKHexEditorColors.DigitTextOdd) color property } + cDigitTextOddDef = clRed; + { Default value for the @link(TKHexEditorColors.DigitBkGnd) color property } + cDigitBkGndDef = clWindow; + { Default value for the @link(TKHexEditorColors.HorzLines) color property } + cHorzLinesDef = clWindowText; + { Default value for the @link(TKHexEditorColors.InactiveCaretBkGnd) color property } + cInactiveCaretBkGndDef = clBlack; + { Default value for the @link(TKHexEditorColors.InactiveCaretSelBkGnd) color property } + cInactiveCaretSelBkGndDef = clBlack; + { Default value for the @link(TKHexEditorColors.InactiveCaretSelText) color property } + cInactiveCaretSelTextDef = clYellow; + { Default value for the @link(TKHexEditorColors.InactiveCaretText) color property } + cInactiveCaretTextDef = clYellow; + { Default value for the @link(TKHexEditorColors.LinesHighLight) color property } + cLinesHighLightDef = clHighLightText; + { Default value for the @link(TKHexEditorColors.SelBkGnd) color property } + cSelBkGndDef = clGrayText; + { Default value for the @link(TKHexEditorColors.SelBkGndFocused) color property } + cSelBkGndFocusedDef = clHighlight; + { Default value for the @link(TKHexEditorColors.SelText) color property } + cSelTextDef = clHighlightText; + { Default value for the @link(TKHexEditorColors.SelTextFocused) color property } + cSelTextFocusedDef = clHighlightText; + { Default value for the @link(TKHexEditorColors.Separators) color property } + cSeparatorsDef = clWindowText; + { Default value for the @link(TKHexEditorColors.TextText) color property } + cTextTextDef = clWindowText; + { Default value for the @link(TKHexEditorColors.TextBkgnd) color property } + cTextBkgndDef = clWindow; + { Default value for the @link(TKHexEditorColors.VertLines) color property } + cVertLinesDef = clWindowText; + + { Index for the @link(TKHexEditorColors.AddressText) color property } + ciAddressText = TKHexEditorColorIndex(0); + { Index for the @link(TKHexEditorColors.AddressBkGnd) color property } + ciAddressBkGnd = TKHexEditorColorIndex(1); + { Index for the @link(TKHexEditorColors.BkGnd) color property } + ciBkGnd = TKHexEditorColorIndex(2); + { Index for the @link(TKHexEditorColors.DigitTextEven) color property } + ciDigitTextEven = TKHexEditorColorIndex(3); + { Index for the @link(TKHexEditorColors.DigitTextOdd) color property } + ciDigitTextOdd = TKHexEditorColorIndex(4); + { Index for the @link(TKHexEditorColors.DigitBkGnd) color property } + ciDigitBkGnd = TKHexEditorColorIndex(5); + { Index for the @link(TKHexEditorColors.HorzLines) color property } + ciHorzLines = TKHexEditorColorIndex(6); + { Index for the @link(TKHexEditorColors.InactiveCaretBkGnd) color property } + ciInactiveCaretBkGnd = TKHexEditorColorIndex(7); + { Index for the @link(TKHexEditorColors.InactiveCaretSelBkGnd) color property } + ciInactiveCaretSelBkGnd = TKHexEditorColorIndex(8); + { Index for the @link(TKHexEditorColors.InactiveCaretSelText) color property } + ciInactiveCaretSelText = TKHexEditorColorIndex(9); + { Index for the @link(TKHexEditorColors.InactiveCaretText) color property } + ciInactiveCaretText = TKHexEditorColorIndex(10); + { Index for the @link(TKHexEditorColors.LinesHighLight) color property } + ciLinesHighLight = TKHexEditorColorIndex(11); + { Index for the @link(TKHexEditorColors.SelBkGnd) color property } + ciSelBkGnd = TKHexEditorColorIndex(12); + { Index for the @link(TKHexEditorColors.SelBkGndFocused) color property } + ciSelBkGndFocused = TKHexEditorColorIndex(13); + { Index for the @link(TKHexEditorColors.SelText) color property } + ciSelText = TKHexEditorColorIndex(14); + { Index for the @link(TKHexEditorColors.SelTextFocused) color property } + ciSelTextFocused = TKHexEditorColorIndex(15); + { Index for the @link(TKHexEditorColors.Separators) color property } + ciSeparators = TKHexEditorColorIndex(16); + { Index for the @link(TKHexEditorColors.TextText) color property } + ciTextText = TKHexEditorColorIndex(17); + { Index for the @link(TKHexEditorColors.TextBkgnd) color property } + ciTextBkGnd = TKHexEditorColorIndex(18); + { Index for the @link(TKHexEditorColors.VertLines) color property } + ciVertLines = TKHexEditorColorIndex(19); + { Maximum color array index } + ciHexEditorColorsMax = ciVertLines; + + { Default value for the @link(TKCustomHexEditor.AddressMode) property } + cAddressModeDef = eamHex; + + { Default value for the @link(TKCustomHexEditor.Addressoffset) property } + cAddressOffsetDef = 0; + + { Default value for the @link(TKCustomHexEditor.DisabledDrawStyle) property } + cDisabledDrawStyleDef = eddBright; + + { Default value for the @link(TKCustomHexEditor.DrawStyles) property } + cDrawStylesDef = [edAddress, edDigits, edText, edInactiveCaret, edSeparators]; + + { Default value for the @link(TKCustomHexEditor.AddressPrefix) property } + cAddressPrefixDef = '0x'; + + { Default value for the @link(TKHexEditor.Font).Name property } + cFontNameDef = {$IFDEF MSWINDOWS}'Courier New'{$ELSE}'Courier'{$ENDIF}; + + { Default value for the @link(TKHexEditor.Font).Style property } + cFontStyleDef = [fsBold]; + + { Declares the Index member of the @link(TKHexEditorSelection) record invalid} + cInvalidIndex = -1; + + { Default value for the @link(TKCustomHexEditor.AddressCursor) property } + cAddressCursorDef = crHandPoint; + + { Default value for the @link(TKHexEditor.Height) property } + cHeight = 300; + + { Default value for the @link(TKHexEditor.Width) property } + cWidth = 400; + +type + TKCustomHexEditor = class; + + { @abstract(Container for all colors used by @link(TKCustomHexEditor) class) + This container allows to group many colors into one item in object inspector. + Colors are accessible via published properties or several public Color* + properties. + } + TKHexEditorColors = class(TPersistent) + private + FOwner: TKCustomHexEditor; + FBrightColors: TKColorArray; + FColors: TKColorArray; + FColorScheme: TKHexEditorColorScheme; + FSingleBkGnd: Boolean; + function GetColor(Index: TKHexEditorColorIndex): TColor; + function GetColorData(Index: TKHexEditorColorIndex): TKHexEditorColorData; + function GetColorEx(Index: TKHexEditorColorIndex): TColor; + function GetColorName(Index: TKHexEditorColorIndex): string; + procedure SetColor(Index: TKHexEditorColorIndex; Value: TColor); + procedure SetColorEx(Index: TKHexEditorColorIndex; Value: TColor); + procedure SetColors(const Value: TKColorArray); + public + { Performs necessary initializations } + constructor Create(AOwner: TKCustomHexEditor); + { Takes property values from another TKHexEditorColors class } + procedure Assign(Source: TPersistent); override; + { Clears cached brighter colors } + procedure ClearBrightColors; + { Initializes the color array. } + procedure Initialize; virtual; + { Specifies color scheme for reading of published properties - see GetColor in source code} + property ColorScheme: TKHexEditorColorScheme read FColorScheme write FColorScheme; + { Returns always normal color - regardless of the ColorScheme setting } + property Color[Index: TKHexEditorColorIndex]: TColor read GetColorEx write SetColorEx; + { Returns always a complete color description } + property ColorData[Index: TKHexEditorColorIndex]: TKHexEditorColorData read GetColorData; + { Returns (localizable) color name } + property ColorName[Index: TKHexEditorColorIndex]: string read GetColorName; + { Returns array of normal colors } + property Colors: TKColorArray read FColors write SetColors; + { @link(TKHexEditorColors.BkGnd) is used for all areas if True - @link(edSingleBkGnd) forward } + property SingleBkGnd: Boolean read FSingleBkGnd write FSingleBkGnd; + published + { Address area text color } + property AddressText: TColor index ciAddressText read GetColor write SetColor default cAddressTextDef; + { Address area background color } + property AddressBkGnd: TColor index ciAddressBkgnd read GetColor write SetColor default cAddressBkGndDef; + { Hex editor client area background } + property BkGnd: TColor index ciBkGnd read GetColor write SetColor default cBkGndDef; + { Digits area text color - even digit group } + property DigitTextEven: TColor index ciDigitTextEven read GetColor write SetColor default cDigitTextEvenDef; + { Digits area text color - odd digit group } + property DigitTextOdd: TColor index ciDigitTextOdd read GetColor write SetColor default cDigitTextOddDef; + { Digits area background color } + property DigitBkGnd: TColor index ciDigitBkGnd read GetColor write SetColor default cDigitBkGndDef; + { Color of the horizontal leading lines } + property HorzLines: TColor index ciHorzLines read GetColor write SetColor default cHorzLinesDef; + { Inactive (hex editor without focus) caret background color - caret mark is not part of a selection } + property InactiveCaretBkGnd: TColor index ciInactiveCaretBkGnd read GetColor write SetColor default cInactiveCaretBkGndDef; + { Inactive (hex editor without focus) caret background color - caret mark is part of a selection } + property InactiveCaretSelBkGnd: TColor index ciInactiveCaretSelBkGnd read GetColor write SetColor default cInactiveCaretSelBkGndDef; + { Inactive (hex editor without focus) caret text color - caret mark is part of a selection } + property InactiveCaretSelText: TColor index ciInactiveCaretSelText read GetColor write SetColor default cInactiveCaretSelTextDef; + { Inactive (hex editor without focus) caret text color - caret mark is not part of a selection } + property InactiveCaretText: TColor index ciInactiveCaretText read GetColor write SetColor default cInactiveCaretTextDef; + { Color of horizontal leading lines involved into a selection } + property LinesHighLight: TColor index ciLinesHighLight read GetColor write SetColor default cLinesHighLightDef; + { Selection background - inactive edit area } + property SelBkGnd: TColor index ciSelBkGnd read GetColor write SetColor default cSelBkGndDef; + { Selection background - active edit area } + property SelBkGndFocused: TColor index ciSelBkGndFocused read GetColor write SetColor default cSelBkGndFocusedDef; + { Selection text - inactive edit area } + property SelText: TColor index ciSelText read GetColor write SetColor default cSelTextDef; + { Selection text - active edit area } + property SelTextFocused: TColor index ciSelTextFocused read GetColor write SetColor default cSelTextFocusedDef; + { Color of the vertical area separating lines } + property Separators: TColor index ciSeparators read GetColor write SetColor default cSeparatorsDef; + { Text area text color } + property TextText: TColor index ciTextText read GetColor write SetColor default cTextTextDef; + { Text area background color } + property TextBkgnd: TColor index ciTextBkgnd read GetColor write SetColor default cTextBkGndDef; + { Color of the vertical leading lines } + property VertLines: TColor index ciVertLines read GetColor write SetColor default cVertLinesDef; + end; + + { Declares possible values for the ItemReason member of the @link(TKHexEditorChangeItem) structure } + TKHexEditorChangeReason = ( + { Save caret position only } + crCaretPos, + { Save inserted character to be able to delete it } + crDeleteChar, + { Save inserted hexadecimal digits to be able to delete them } + crDeleteDigits, + { Save inserted binary string to be able to delete it } + crDeleteString, + { Save deleted character to be able to insert it } + crInsertChar, + { Save deleted hexadecimal digits to be able to insert them } + crInsertDigits, + { Save deleted binary string to be able to insert it } + crInsertString + ); + + { @abstract(Declares @link(TKHexEditorChangeList.OnChange) event handler) +
    + Parameters: +
  • Sender - identifies the event caller
  • +
  • ItemReason - specifies the undo/redo reason
  • +
+ } + TKHexEditorUndoChangeEvent = procedure(Sender: TObject; + ItemReason: TKHexEditorChangeReason) of object; + + { @abstract(Declares the undo/redo item description structure used by the @link(TKHexEditorChangeList) class) +
    + Members: +
  • Data - characters (binary or digit string) needed to execute this item
  • +
  • EditArea - active edit area at the time this item was recorded
  • +
  • Group - identifies the undo/redo group. Some editor modifications + produce a sequence of 2 or more undo items. This sequence is called undo/redo + group and is always interpreted as a single undo/redo item. Moreover, + if there is eoGroupUndo in @link(TKCustomHexEditor.Options), + a single ecUndo or ecRedo command manipulates all following undo groups + of the same kind (reason) as if they were a single undo/redo item.
  • +
  • GroupReason - reason (kind) of this undo group
  • +
  • ItemReason - reason (kind) of this item
  • +
  • SelEnd - end of the selection at the time this item was recorded
  • +
  • SelStart - start of the selection at the time this item was recorded
  • +
+ } + TKHexEditorChangeItem = record + Data: AnsiString; + EditArea: TKHexEditorArea; + Group: Cardinal; + GroupReason: TKHexEditorChangeReason; + Inserted: Boolean; + ItemReason: TKHexEditorChangeReason; + SelEnd: TKHexEditorSelection; + SelStart: TKHexEditorSelection; + end; + + { Pointer to @link(TKHexEditorChangeItem) } + PKHexEditorChangeItem = ^TKHexEditorChangeItem; + + { @abstract(Change (undo/redo item) list manager) } + TKHexEditorChangeList = class(TList) + private + FEditor: TKCustomHexEditor; + FGroup: Cardinal; + FGroupUseLock: Integer; + FGroupReason: TKHexEditorChangeReason; + FIndex: Integer; + FModifiedIndex: Integer; + FLimit: Integer; + FRedoList: TKHexEditorChangeList; + FOnChange: TKHexEditorUndoChangeEvent; + function GetModified: Boolean; + procedure SetLimit(Value: Integer); + procedure SetModified(Value: Boolean); + protected + { Redefined to properly destroy the items } + procedure Notify(Ptr: Pointer; Action: TListNotification); override; + public + { Performs necessary initializations +
    + Parameters: +
  • AEditor - identifies the undo/redo list owner
  • +
  • RedoList - when this instance is used as undo list, specify + a redo list to allow clear it at each valid AddChange call
  • +
} + constructor Create(AEditor: TKCustomHexEditor; RedoList: TKHexEditorChangeList); + { Inserts a undo/redo item +
    + Parameters: +
  • ItemReason - specifies the undo/redo item reason. The change list doesn't + allow to insert succesive crCaretPos items unless Inserted is True
  • +
  • Data - specifies the item data. Some items (crCaretPos) + don't need to supply any data
  • +
  • Inserted - for the urInsert* items, specifies whether the item + was recorded with @link(TKCustomHexEditor.InsertMode) on (True) or + off (False). See ItemReason for crCaretPos behavior.
  • +
} + procedure AddChange(ItemReason: TKHexEditorChangeReason; const Data: AnsiString = ''; + Inserted: Boolean = True); virtual; + { Tells the undo list a new undo/redo group is about to be created. Each + BeginGroup call must have a corresponding EndGroup call (use try-finally). + BeginGroup calls may be nested, however, only the first call will create an + undo/redo group. Use the GroupReason parameter to specify the reason of this group. } + procedure BeginGroup(GroupReason: TKHexEditorChangeReason); virtual; + { Informs whether there are any undo/redo items available - i.e. CanUndo/CanRedo} + function CanPeek: Boolean; + { Clears the entire list - overriden to execute some adjustments } + procedure Clear; override; + { Completes the undo/redo group. See @link(TKHexEditorChangeList.BeginGroup) for details } + procedure EndGroup; virtual; + { Returns the topmost item to handle or inspect it} + function PeekItem: PKHexEditorChangeItem; + { If there is no reason to handle an item returned by PeekItem, it has to be + poked back with this function to become active for next undo/redo command } + procedure PokeItem; + { For redo list only - each undo command creates a redo command with the same + group information - see source } + procedure SetGroupData(Group: Integer; GroupReason: TKHexEditorChangeReason); + { Specifies maximum number of items - not groups } + property Limit: Integer read FLimit write SetLimit; + { For undo list only - returns True if undo list contains some items with regard + to the eoUndoAfterSave option } + property Modified: Boolean read GetModified write SetModified; + { Allows to call TKCustomHexEditor.@link(TKCustomHexEditor.OnChange) event} + property OnChange: TKHexEditorUndoChangeEvent read FOnChange write FOnChange; + end; + + { @abstract(Hexadecimal editor base component) } + TKCustomHexEditor = class(TKCustomControl) + private + FAddressCursor: TCursor; + FAddressMode: TKHexEditorAddressMode; + FAddressOffset: Integer; + FAddressPrefix: string; + FAddressSize: Integer; + FAreaSpacing: Integer; + FBuffer: PBytes; + FCharHeight: Integer; + FCharMapping: TKEditCharMapping; + FCharSpacing: Integer; + FCharWidth: Integer; + FClipboardFormat: Word; + FColors: TKHexEditorColors; + FDigitGrouping: Integer; + FDisabledDrawStyle: TKHexEditorDisabledDrawStyle; + FDrawStyles: TKHexEditorDrawStyles; + FEditArea: TKHexEditorArea; + FKeyMapping: TKEditKeyMapping; + FLeftChar: Integer; + FLineHeightPercent: Integer; + FLineSize: Integer; + FMouseWheelAccumulator: Integer; + FOptions: TKEditOptions; + FRedoList: TKHexEditorChangeList; + FScrollBars: TScrollStyle; + FScrollDeltaX: Integer; + FScrollDeltaY: Integer; + FScrollSpeed: Cardinal; + FScrollTimer: TTimer; + FSelEnd: TKHexEditorSelection; + FSelStart: TKHexEditorSelection; + FSize: Integer; + FStates: TKHexEditorStates; + FTopLine: Integer; + FTotalCharSpacing: Integer; + FUndoList: TKHexEditorChangeList; + FOnChange: TNotifyEvent; + FOnDropFiles: TKEditDropFilesEvent; + FOnReplaceText: TKEditReplaceTextEvent; + function GetCommandKey(Index: TKEditCommand): TKEditKey; + function GetCaretVisible: Boolean; + function GetData: TDataSize; + function GetEmpty: Boolean; + function GetFirstVisibleIndex: Integer; + function GetInsertMode: Boolean; + function GetLastVisibleIndex: Integer; + function GetLineCount: Integer; + function GetLines(Index: Integer): TDataSize; + function GetModified: Boolean; + function GetReadOnly: Boolean; + function GetSelLength: TKHexEditorSelection; + function GetSelText: TKHexEditorSelText; + function GetUndoLimit: Integer; + function IsAddressPrefixStored: Boolean; + function IsDrawStylesStored: Boolean; + function IsOptionsStored: Boolean; + procedure ScrollTimerHandler(Sender: TObject); + procedure SetAddressCursor(Value: TCursor); + procedure SetAddressMode(Value: TKHexEditorAddressMode); + procedure SetAddressOffset(Value: Integer); + procedure SetAddressPrefix(const Value: string); + procedure SetAddressSize(Value: Integer); + procedure SetAreaSpacing(Value: Integer); + procedure SetCharSpacing(Value: Integer); + procedure SetColors(Value: TKHexEditorColors); + procedure SetCommandKey(Index: TKEditCommand; Value: TKEditKey); + procedure SetData(Value: TDataSize); + procedure SetDigitGrouping(Value: Integer); + procedure SetDisabledDrawStyle(Value: TKHexEditorDisabledDrawStyle); + procedure SetDrawStyles(const Value: TKHexEditorDrawStyles); + procedure SetEditArea(Value: TKHexEditorArea); + procedure SetLeftChar(Value: Integer); + procedure SetLineHeightPercent(Value: Integer); + procedure SetLines(Index: Integer; const Value: TDataSize); + procedure SetLineSize(Value: Integer); + procedure SetModified(Value: Boolean); + procedure SetOptions(const Value: TKEditOptions); + procedure SetReadOnly(Value: Boolean); + procedure SetScrollBars(Value: TScrollStyle); + procedure SetScrollSpeed(Value: Cardinal); + procedure SetSelEnd(Value: TKHexEditorSelection); + procedure SetSelLength(Value: TKHexEditorSelection); + procedure SetSelStart(Value: TKHexEditorSelection); + procedure SetTopLine(Value: Integer); + procedure SetUndoLimit(Value: Integer); + procedure CMEnabledChanged(var Msg: TLMessage); message CM_ENABLEDCHANGED; + procedure CMSysColorChange(var Msg: TLMessage); message CM_SYSCOLORCHANGE; + {$IFNDEF FPC} + // no way to get filenames in Lazarus inside control (why??) + procedure WMDropFiles(var Msg: TLMessage); message LM_DROPFILES; + {$ENDIF} + procedure WMEraseBkgnd(var Msg: TLMessage); message LM_ERASEBKGND; + procedure WMGetDlgCode(var Msg: TLMNoParams); message LM_GETDLGCODE; + procedure WMHScroll(var Msg: TLMHScroll); message LM_HSCROLL; + procedure WMKillFocus(var Msg: TLMKillFocus); message LM_KILLFOCUS; + procedure WMSetFocus(var Msg: TLMSetFocus); message LM_SETFOCUS; + procedure WMVScroll(var Msg: TLMVScroll); message LM_VSCROLL; + protected + { Inserts a single crCaretPos item into undo list. Unless Force is set to True, + this change will be inserted only if previous undo item is not crCaretPos. } + procedure AddUndoCaretPos(Force: Boolean = True); + { Inserts a single byte change into undo list. +
    + Parameters: +
  • ItemReason - specifies the undo/redo item reason - most likely + crInsertChar or crDeleteChar.
  • +
  • Data - specifies the data byte needed to restore the original + buffer state
  • +
  • Inserted - for the urInsert* items, specifies the current + @link(TKCustomHexEditor.InsertMode) status.
  • +
} + procedure AddUndoByte(ItemReason: TKHexEditorChangeReason; Data: Byte; + Inserted: Boolean = True); + { Inserts a byte array change into undo list. +
    + Parameters: +
  • ItemReason - specifies the undo/redo item reason - crInsert* or + crDelete*.
  • +
  • Data - specifies the data bytes needed to restore the original + buffer state
  • +
  • Inserted - for the urInsert* items, specifies the current + @link(TKCustomHexEditor.InsertMode) status.
  • +
} + procedure AddUndoBytes(ItemReason: TKHexEditorChangeReason; Data: PBytes; + Length: Integer; Inserted: Boolean = True); + { Inserts a string change into undo list. Has the same functionality as AddUndoBytes + only Data is supplied as a string. } + procedure AddUndoString(ItemReason: TKHexEditorChangeReason; const S: AnsiString; + Inserted: Boolean = True); + { Begins a new undo group. Use the GroupReason parameter to label it. } + procedure BeginUndoGroup(GroupReason: TKHexEditorChangeReason); + { Performs necessary adjustments when the buffer is modified programatically + (not by user) } + procedure BufferChanged; + { Determines whether an ecScroll* command can be executed } + function CanScroll(Command: TKEditCommand): Boolean; virtual; + { Clears a character at position At. Doesn't perform any succesive adjustments. } + procedure ClearChar(At: Integer); + { Clears a the digit fields both in SelStart and SelEnd. Doesn't perform any succesive adjustments.} + procedure ClearDigitSelection; + { Clears a string of the Size length at position At. Doesn't perform any succesive adjustments. } + procedure ClearString(At, Size: Integer); + { Overriden method - defines additional styles for the hex editor window (scrollbars etc.)} + procedure CreateParams(var Params: TCreateParams); override; + { Overriden method - adjusts file drag&drop functionality } + procedure CreateWnd; override; + { Overriden method - adjusts file drag&drop functionality } + procedure DestroyWnd; override; + { Calls the @link(TKCustomHexEditor.OnChange) event } + procedure DoChange; virtual; + { Overriden method - handles mouse wheel messages } + function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; + MousePos: TPoint): Boolean; override; + { Validates the EditArea property after it has been modified } + procedure EditAreaChanged; virtual; + { Closes the undo group created by @link(TKCustomHexEditor.BeginUndoGroup) } + procedure EndUndoGroup; + { Ensures that font pitch is always fpFixed and Font.Size is not too small or big } + procedure FontChange(Sender: TObject); virtual; + { Returns the horizontal page extent for the current edit area. This function is + used by the ecPageLeft and ecPageRight commands. } + function GetPageHorz: Integer; virtual; + { Determines if the editor has input focus. } + function HasFocus: Boolean; virtual; + { Hides the caret. } + procedure HideEditorCaret; virtual; + { Inserts a character at specified position. Doesn't perform any succesive adjustments. +
    + Parameters: +
  • At - position where the character should be inserted.
  • +
  • Value - character (data byte)
  • +
} + procedure InsertChar(At: Integer; Value: Byte); + { Inserts a string at specified position. Doesn't perform any succesive adjustments. +
    + Parameters: +
  • At - position where the string should be inserted.
  • +
  • Value - data byte string
  • +
  • Size - length of the data byte string
  • +
} + procedure InsertString(At: Integer; const Value: AnsiString; Size: Integer); + { Returns True if the control has a selection. } + function InternalGetSelAvail: Boolean; override; + { Moves the caret one position left. Doesn't perform any succesive adjustments.} + procedure InternalMoveLeft; virtual; + { Moves the caret one position right. Doesn't perform any succesive adjustments.} + procedure InternalMoveRight; virtual; + { Overriden method - processes virtual key strokes according to current @link(TKCustomHexEditor.KeyMapping) } + procedure KeyDown(var Key: Word; Shift: TShiftState); override; + { Overriden method - processes character key strokes - data editing } + procedure KeyPress(var Key: Char); override; + { Updates information about printed shape. } + procedure MeasurePages(var Info: TKPrintMeasureInfo); override; + { Processes scrollbar messages. +
    + Parameters: +
  • ScrollBar - scrollbar type from OS
  • +
  • ScrollCode - scrollbar action from OS
  • +
  • Delta - scrollbar position change
  • +
  • UpdateNeeded - set to True if you want to invalidate + and update caret position
  • +
} + procedure ModifyScrollBar(ScrollBar, ScrollCode, Delta: Integer; + UpdateNeeded: Boolean); + { Overriden method - updates caret position/selection } + procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; + { Overriden method - updates caret position/selection and initializes scrolling + when needed. } + procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; + { Overriden method - releases mouse capture acquired by MouseDown } + procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; + { Overriden method - calls PaintLines for drawing the hex editor outline + into window client area } + procedure PaintToCanvas(ACanvas: TCanvas); override; + { Paints/prints hex editor outline. This function must retain its reentrancy. +
    + Parameters: +
  • Data - paint settings
  • +
} + procedure PaintLines(const Data: TKHexEditorPaintData); virtual; + { Paints a page to a printer/preview canvas. } + procedure PaintPage; override; + { Grants the input focus to the control when possible and the control has had none before } + procedure SafeSetFocus; + { Performs necessary adjustments after a selection property changed. +
    + Parameters: +
  • StartEqualEnd - forces SelStart equal to SelEnd
  • +
  • ScrollToView - forces scrolling if SelEnd (caret) became invisible
  • +
} + procedure SelectionChanged(StartEqualEnd: Boolean; ScrollToView: Boolean = True); + { Scrolls the hex editor window horizontaly by HChars characters and/or + vertically by VChars characters } + procedure ScrollBy(HChars, VChars: Integer; UpdateNeeded: Boolean); + { Scrolls the hex editor window to ensure data under defined (mouse) coordinates are visible +
    + Parameters: +
  • Point - (mouse) coordinates
  • +
  • Timed - set to True to continue scroll via a timer. The scrolling + will continue until the mouse cursor is outside of the modified client rect + (@link(TKCustomHexEditor.GetModifiedClientRect)).
  • +
  • AlwaysScroll - set to True to disable new line overscrolling
  • +
} + procedure ScrollTo(Point: TPoint; Timed, AlwaysScroll: Boolean); virtual; + { Updates mouse cursor according to the state determined from current mouse + position. Returns True if cursor has been changed. } + function SetMouseCursor(X, Y: Integer): Boolean; override; + { Shows the caret. } + procedure ShowEditorCaret; virtual; + { Calls the @link(TKCustomHexEditor.DoChange) method} + procedure UndoChange(Sender: TObject; ItemReason: TKHexEditorChangeReason); + { Updates caret position, shows/hides caret according to the input focus +
    + Parameters: +
  • Recreate - set to True to recreate the caret after it has already + been created and displayed
  • +
} + procedure UpdateEditorCaret(Recreate: Boolean = False); virtual; + { Updates font based dimensions } + procedure UpdateCharMetrics; virtual; + { Updates mouse cursor } + procedure UpdateMouseCursor; virtual; + { Updates the scrolling range } + procedure UpdateScrollRange; virtual; + { Updates selection according to the supplied coordinates. +
    + Parameters: +
  • Point - specifies the coordinates
  • +
  • ClipToClient - specifies whether the coordinates should be clipped + to modified client rectangle (@link(TKCustomHexEditor.GetModifiedClientRect)) + first
  • +
} + procedure UpdateSelEnd(Point: TPoint; ClipToClient: Boolean); virtual; + { Updates the control size. } + procedure UpdateSize; override; + { Data buffer - made accessible for descendant classes } + property Buffer: PBytes read FBuffer write FBuffer; + { Redo list manager - made accessible for descendant classes } + property RedoList: TKHexEditorChangeList read FRedoList; + { Data buffer size - made accessible for descendant classes } + property Size: Integer read FSize write FSize; + { States of this class - made accessible for descendant classes } + property States: TKHexEditorStates read FStates write FStates; + { Undo list manager - made accessible for descendant classes } + property UndoList: TKHexEditorChangeList read FUndoList; + public + { Performs necessary initializations - default values to properties, create + undo/redo list managers } + constructor Create(AOwner: TComponent); override; + { Destroy instance, undo/redo list managers, dispose buffer... } + destructor Destroy; override; + { Appends data at current position. Use TKHexEditor.Data.Size for At parameter + to append at the end of the buffer. } + procedure Append(At: Integer; Data: TDataSize); overload; virtual; + { Appends data at current position. Use TKHexEditor.Data.Size for At parameter + to append at the end of the buffer. } + procedure Append(At: Integer; const Data: AnsiString); overload; virtual; + { Takes property values from another TKCustomHexEditor class } + procedure Assign(Source: TPersistent); override; + { Determines whether the caret is visible } + function CaretInView: Boolean; + { Clears entire data buffer. Unlike ecClearAll this method clears everything + inclusive undo a redo lists. } + procedure Clear; + { Clears undo (and redo) list } + procedure ClearUndo; + { Determines whether given command can be executed at this time. Use this + function in TAction.OnUpdate events. +
    + Parameters: +
  • Command - specifies the command to inspect
  • +
} + function CommandEnabled(Command: TKEditCommand): Boolean; virtual; + { Executes given command. This function first calls CommandEnabled to + assure given command can be executed. +
    + Parameters: +
  • Command - specifies the command to execute
  • +
  • Data - specifies the data needed for the command
  • +
} + function ExecuteCommand(Command: TKEditCommand; Data: Pointer = nil): Boolean; virtual; + { Returns dimensions of all 3 possible areas according to current area + definition } + function GetAreaDimensions: TKHexEditorAreaDimensions; virtual; + { Returns current character mapping. } + function GetCharMapping: TKEditCharMapping; + { Returns number of characters that vertically fit into client window } + function GetClientHeightChars: Integer; virtual; + { Returns number of characters that horizontally fit into client window } + function GetClientWidthChars: Integer; virtual; + { Returns the current key stroke mapping scheme. } + function GetKeyMapping: TKEditKeyMapping; + { Returns modified client rect - a window client rect aligned to character width and + character height } + function GetModifiedClientRect: TRect; virtual; + { Returns current maximum value for the @link(TKCustomHexEditor.LeftChar) property +
    + Parameters: +
  • Extent - specify @link(TKHexEditorAreaDimensions).TotalHorz + here, otherwise the function calculates it itself
  • +
} + function GetMaxLeftChar(Extent: Integer = 0): Integer; virtual; + { Returns current maximum value for the @link(TKCustomHexEditor.TopLine) property +
    + Parameters: +
  • Extent - specify @link(TKHexEditorAreaDimensions).TotalVert + here, otherwise the function calculates it itself
  • +
} + function GetMaxTopLine(Extent: Integer = 0): Integer; virtual; + { Returns "real" selection end - with always higher index value than selection + start value } + function GetRealSelEnd: TKHexEditorSelection; + { Returns "real" selection start - with always lower index value than selection + end value } + function GetRealSelStart: TKHexEditorSelection; + { Loads data from a file } + procedure LoadFromFile(const FileName: TFileName); + { Loads data from a stream - stream position remains untouched } + procedure LoadFromStream(Stream: TStream); + { Paints the editor outline to another canvas +
    + Parameters: +
  • ACanvas - canvas to paint the outline to
  • +
  • ARect - given rectangle in the canvas
  • +
  • ALeftChar - first left visible character
  • +
  • ATopLine - first top visible line
  • +
} + procedure PaintToCanvasEx(ACanvas: TCanvas; ARect: TRect; ALeftChar, ATopLine: Integer); + { Converts window coordinates into a selection +
    + Parameters: +
  • P - window client coordinates
  • +
  • OutOfArea - uses the Area parameter to compute selection for + this area even if the supplied coordinates are outside of the area outline
  • +
  • Area output parameter if OutOfArea = False, otherwise + input parameter
  • +
} + function PointToSel(P: TPoint; OutOfArea: Boolean; var Area: TKHexEditorArea): TKHexEditorSelection; virtual; + { Saves data into a file } + procedure SaveToFile(const FileName: TFileName); + { Saves data into a stream - stream position remains untouched } + procedure SaveToStream(Stream: TStream); + { Determines whether a seletion (not digit selection) is available } + function SelAvail: Boolean; + { Determines whether a given selection is valid for given area +
    + Parameters: +
  • Value - selection to examine
  • +
  • Area - area for which the selection must be examined
  • +
} + function SelectionValid(Value: TKHexEditorSelection; Area: TKHexEditorArea): Boolean; virtual; + { Converts a selection into window coordinates +
    + Parameters: +
  • Value - selection to convert
  • +
  • Area - the same selection delivers another coordinates for each area
  • +
} + function SelToPoint(Value: TKHexEditorSelection; Area: TKHexEditorArea): TPoint; virtual; + { Specifies character mapping. The main purpose of this is to avoid non-printable + characters in the text area and in AsText copies. Avoid non-printable characters + when delivering a new character mapping. } + procedure SetCharMapping(const Value: TKEditCharMapping); + { Specifies the current key stroke mapping scheme } + procedure SetKeyMapping(const Value: TKEditKeyMapping); + { Validates a selection for given area +
    + Parameters: +
  • Value - selection to validate
  • +
  • Area - area for which the selection must be validated
  • +
} + procedure ValidateSelection(var Value: TKHexEditorSelection; Area: TKHexEditorArea); virtual; + { Specifies the address area mouse cursor. Other areas have crIBeam - should not + be needed to modify that } + property AddressCursor: TCursor read FAddressCursor write SetAddressCursor default cAddressCursorDef; + { Specifies the radix of addresses } + property AddressMode: TKHexEditorAddressMode read FAddressMode write SetAddressMode default cAddressModeDef; + { Specifies the address offset } + property AddressOffset: Integer read FAddressOffset write SetAddressOffset default cAddressOffsetDef; + { Specifies the address number prefix i.e. 0x or $ - modify together with AddressMode } + property AddressPrefix: string read FAddressPrefix write SetAddressPrefix stored IsAddressPrefixStored; + { Specifies the number of address digits - up to 10 for decimal addresses } + property AddressSize: Integer read FAddressSize write SetAddressSize default cAddressSizeDef; + { Defines space between neighbour areas } + property AreaSpacing: Integer read FAreaSpacing write SetAreaSpacing default cAreaSpacingDef; + { Returns current caret position = selection end } + property CaretPos: TKHexEditorSelection read FSelEnd; + { Returns True if caret is visible } + property CaretVisible: Boolean read GetCaretVisible; + { Returns current character width = not necessarily equal to font character width } + property CharWidth: Integer read FCharWidth; + { Defines additional inter-character spacing } + property CharSpacing: Integer read FCharSpacing write SetCharSpacing default cCharSpacingDef; + { Returns current character height = not equal to font character height } + property CharHeight: Integer read FCharHeight; + { Returns the binary data clipboard format } + property ClipboardFormat: Word read FClipboardFormat; + { Makes it possible to take all color properties from another TKCustomHexEditor class } + property Colors: TKHexEditorColors read FColors write SetColors; + { Specifies a new key stroke combination for given command } + property CommandKey[Index: TKEditCommand]: TKEditKey read GetCommandKey write SetCommandKey; + { This property provides direct access to the data buffer } + property Data: TDataSize read GetData write SetData; + { Specifies the byte grouping in the digits area } + property DigitGrouping: Integer read FDigitGrouping write SetDigitGrouping default cDigitGroupingDef; + { Specifies the style how the outline is drawn when editor is disabled } + property DisabledDrawStyle: TKHexEditorDisabledDrawStyle read FDisabledDrawStyle write SetDisabledDrawStyle default cDisabledDrawStyleDef; + { Defines areas to paint, whether to paint horizontal and vertical trailing lines, + area separator lines and caret mark when the editor has no input focus } + property DrawStyles: TKHexEditorDrawStyles read FDrawStyles write SetDrawStyles stored IsDrawStylesStored; + { Specifies the current area for editing } + property EditArea: TKHexEditorArea read FEditArea write SetEditArea default eaDigits; + { Returns True if data buffer is empty } + property Empty: Boolean read GetEmpty; + { Returns the first visible index } + property FirstVisibleIndex: Integer read GetFirstVisibleIndex; + { Returns True if insert mode is on } + property InsertMode: Boolean read GetInsertMode; + { Returns the last visible index } + property LastVisibleIndex: Integer read GetLastVisibleIndex; + { Specifies the horizontal scroll position } + property LeftChar: Integer read FLeftChar write SetLeftChar; + { Determines the number of lines } + property LineCount: Integer read GetLineCount; + { Specifies the line height. 100% is the current font height } + property LineHeightPercent: Integer read FLineHeightPercent write SetLineHeightPercent default cLineHeightPercentDef; + { Allows to modify/add data lines. If greater than LineSize, the Size member + of the supplied TDataSize structure will be always trimmed to LineSize. + If Index points to last incomplete line or even higher, last line will be + extended/completed, i.e new data will be added to the buffer } + property Lines[Index: Integer]: TDataSize read GetLines write SetLines; + { Specifies the size (length) of a single line } + property LineSize: Integer read FLineSize write SetLineSize default cLineSizeDef; + { Returns True if the buffer was modified - eoUndoAfterSave taken into + account } + property Modified: Boolean read GetModified write SetModified; + { Specifies the editor options that do not affect painting } + property Options: TKEditOptions read FOptions write SetOptions stored IsOptionsStored; + { Specifies whether the editor has to be read only editor } + property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False; + { Defines visible scrollbars - horizontal, vertical or both } + property ScrollBars: TScrollStyle read FScrollBars write SetScrollBars default ssBoth; + { Specifies how fast the scrolling by timer should be } + property ScrollSpeed: Cardinal read FScrollSpeed write SetScrollSpeed default cScrollSpeedDef; + { Specifies the current selection end } + property SelEnd: TKHexEditorSelection read FSelEnd write SetSelEnd; + { Specifies the current selection length. SelStart remains unchanged, SelEnd will be + updated accordingly. To mark a selection, either set both SelStart and SelEnd properties + or both SelStart and SelLength properties } + property SelLength: TKHexEditorSelection read GetSelLength write SetSelLength; + { Specifies the current selection start } + property SelStart: TKHexEditorSelection read FSelStart write SetSelStart; + { Returns selected text in many different formats } + property SelText: TKHexEditorSelText read GetSelText; + { Specifies the vertical scroll position } + property TopLine: Integer read FTopLine write SetTopLine; + { Specifies the maximum number of undo items. Please note this value + affects the undo item limit, not undo group limit. } + property UndoLimit: Integer read GetUndoLimit write SetUndoLimit default cUndoLimitDef; + { When assigned, this event will be invoked at each buffer change, made either + by the user or programmatically by public functions } + property OnChange: TNotifyEvent read FOnChange write FOnChange; + { When assigned, this event will be invoked when the user drops any files onto + the window } + property OnDropFiles: TKEditDropFilesEvent read FOnDropFiles write FOnDropFiles; + { When assigned, this event will be invoked at each prompt-forced search match } + property OnReplaceText: TKEditReplaceTextEvent read FOnReplaceText write FOnReplaceText; + end; + + { @abstract(Hexadecimal editor design-time component) } + TKHexEditor = class(TKCustomHexEditor) + published + { See TKCustomHexEditor.@link(TKCustomHexEditor.AddressCursor) for details } + property AddressCursor; + { See TKCustomHexEditor.@link(TKCustomHexEditor.AddressMode) for details } + property AddressMode; + { See TKCustomHexEditor.@link(TKCustomHexEditor.AddressOffset) for details } + property AddressOffset; + { See TKCustomHexEditor.@link(TKCustomHexEditor.AddressPrefix) for details } + property AddressPrefix; + { See TKCustomHexEditor.@link(TKCustomHexEditor.AddressSize) for details } + property AddressSize; + { Inherited property - see Delphi help } + property Align; + { Inherited property - see Delphi help } + property Anchors; + { See TKCustomControl.@link(TKCustomControl.BorderStyle) for details } + property BorderStyle; + { Inherited property - see Delphi help } + property BorderWidth; + { See TKCustomHexEditor.@link(TKCustomHexEditor.CharSpacing) for details } + property CharSpacing; + { See TKCustomHexEditor.@link(TKCustomHexEditor.Colors) for details } + property Colors; + { Inherited property - see Delphi help } + property Constraints; + {$IFNDEF FPC} + { Inherited property - see Delphi help. } + property Ctl3D; + {$ENDIF} + { See TKCustomHexEditor.@link(TKCustomHexEditor.DigitGrouping) for details } + property DigitGrouping; + { See TKCustomHexEditor.@link(TKCustomHexEditor.DisabledDrawStyle) for details } + property DisabledDrawStyle; + { Inherited property - see Delphi help } + property DragCursor; + { Inherited property - see Delphi help } + property DragKind; + { Inherited property - see Delphi help } + property DragMode; + { See TKCustomHexEditor.@link(TKCustomHexEditor.DrawStyles) for details } + property DrawStyles; + { See TKCustomHexEditor.@link(TKCustomHexEditor.EditArea) for details } + property EditArea; + { Inherited property - see Delphi help } + property Enabled; + { Inherited property - see Delphi help. Font pitch must always remain fpFixed + - specify fixed fonts only. Font.Size will also be trimmed if too small or big } + property Font; + { Inherited property - see Delphi help } + property Height default cHeight; + { See TKCustomHexEditor.@link(TKCustomHexEditor.LineHeightPercent) for details } + property LineHeightPercent; + { See TKCustomHexEditor.@link(TKCustomHexEditor.LineSize) for details } + property LineSize; + { See TKCustomHexEditor.@link(TKCustomHexEditor.Options) for details } + property Options; + { Inherited property - see Delphi help } + property ParentShowHint; + { Inherited property - see Delphi help } + property PopupMenu; + { See TKCustomHexEditor.@link(TKCustomHexEditor.ReadOnly) for details } + property ReadOnly; + { See TKCustomHexEditor.@link(TKCustomHexEditor.ScrollBars) for details } + property ScrollBars; + { See TKCustomHexEditor.@link(TKCustomHexEditor.ScrollSpeed) for details } + property ScrollSpeed; + { Inherited property - see Delphi help } + property ShowHint; + { Inherited property - see Delphi help } + property TabOrder; + { Inherited property - see Delphi help } + property TabStop default True; + { See TKCustomHexEditor.@link(TKCustomHexEditor.UndoLimit) for details } + property UndoLimit; + { Inherited property - see Delphi help } + property Visible; + { Inherited property - see Delphi help } + property Width default cWidth; + { See TKCustomHexEditor.@link(TKCustomHexEditor.OnChange) for details } + property OnChange; + { Inherited property - see Delphi help } + property OnClick; + { Inherited property - see Delphi help } + property OnContextPopup; + { Inherited property - see Delphi help } + property OnDblClick; + { Inherited property - see Delphi help } + property OnDockDrop; + { Inherited property - see Delphi help } + property OnDockOver; + { Inherited property - see Delphi help } + property OnDragDrop; + { Inherited property - see Delphi help } + property OnDragOver; + { See TKCustomHexEditor.@link(TKCustomHexEditor.OnDropFiles) for details } + property OnDropFiles; + { Inherited property - see Delphi help } + property OnEndDock; + { Inherited property - see Delphi help } + property OnEndDrag; + { Inherited property - see Delphi help } + property OnEnter; + { Inherited property - see Delphi help } + property OnExit; + { Inherited property - see Delphi help } + property OnGetSiteInfo; + { Inherited property - see Delphi help } + property OnKeyDown; + { Inherited property - see Delphi help } + property OnKeyPress; + { Inherited property - see Delphi help } + property OnKeyUp; + { Inherited property - see Delphi help } + property OnMouseDown; + { Inherited property - see Delphi help } + property OnMouseMove; + { Inherited property - see Delphi help } + property OnMouseUp; + { Inherited property - see Delphi help } + property OnMouseWheel; + { Inherited property - see Delphi help } + property OnMouseWheelDown; + { Inherited property - see Delphi help } + property OnMouseWheelUp; + { See TKCustomControl.@link(TKCustomControl.OnPrintNotify) for details } + property OnPrintNotify; + { See TKCustomControl.@link(TKCustomControl.OnPrintPaint) for details } + property OnPrintPaint; + { See TKCustomHexEditor.@link(TKCustomHexEditor.OnReplaceText) for details } + property OnReplaceText; + { Inherited property - see Delphi help } + property OnResize; + { Inherited property - see Delphi help } + property OnStartDock; + { Inherited property - see Delphi help } + property OnStartDrag; + { Inherited property - see Delphi help } + property OnUnDock; + end; + +{ Creates a selection structure from given Index and Digit parameters } +function MakeSelection(Index, Digit: Integer): TKHexEditorSelection; + +{ Converts a hexadecimal digit character ('0'..'F') to binary value } +function DigitToBin(Value: AnsiChar): Integer; + +{ Examines/converts hexadecimal digit string to binary value string. Returns + True if the digit string is valid. +
    + Parameters: +
  • S - hexadecimal digit string (e.g. 'AF01 DC05 3'). White spaces will + be ignored. When Convert is True, the converted binary value string will be returned + via this parameter (in this exammple '#A#F#0#1#D#C#0#5#3').
  • +
  • Convert - the digit string will be converted if True, otherwise it will + be examined only.
  • +
} +function DigitsToBinStr(var S: AnsiString; Convert: Boolean = True): Boolean; + +{ Converts a binary value string into binary data. If the binary value string + is not divisible by 2, it will be right padded with zero. Example: + '#A#F#0#1#D#C#0#5#3' is converted into '#AF#01#DC#05#30'. } +function BinStrToBinary(const S: AnsiString): AnsiString; + +{ Converts binary data into hexadecimal digit string. +
    + Parameters: +
  • Buffer - binary data - intended for @link(TKCustomHexEditor.Buffer)
  • +
  • SelStart, SelEnd - specifies which part of the buffer is about to be + converted. SelStart.Index must be lower or equal to SelEnd.Index - intended for + @link(TKCustomHexEditor.GetRealSelStart) and @link(TKCustomHexEditor.GetRealSelEnd).
  • +
} +function BinaryToDigits(Buffer: PBytes; SelStart, SelEnd: TKHexEditorSelection): AnsiString; + +{ Converts binary data into text using given character mapping. +
    + Parameters: +
  • Buffer - binary data - intended for @link(TKCustomHexEditor.Buffer)
  • +
  • SelStart, SelEnd - specifies which part of the buffer is about to be + converted. SelStart must be lower or equal to SelEnd. These parameters are integers + since no digit selections are necessary.
  • +
  • CharMapping - required character mapping scheme
  • +
} +function BinaryToText(Buffer: PBytes; SelStart, SelEnd: Integer; + CharMapping: PKEditCharMapping): AnsiString; + +{ Replaces a hexadecimal digit in the given binary value. Returns the original + value with a replaced digit. +
    + Parameters: +
  • Value - original binary value
  • +
  • Digit - digit value (0..15)
  • +
  • Pos - digit position (order)
  • +
+ Example: Value = $A18D, Digit = $C, Pos = 3: Result = $AC8D } +function ReplaceDigit(Value, Digit, Pos: Integer): Integer; + +{ Returns the instance-independent color specification for + the given color index } +function GetColorSpec(Index: TKHexEditorColorIndex): TKHexEditorColorSpec; + +implementation + +uses +{$IFDEF USE_THEMES} + Themes, +{$ENDIF} + Math, +{$IFDEF USE_WINAPI} + ShellApi, +{$ENDIF} + ClipBrd, Printers, + Types, KGraphics; + +const + cFmtText = '%.2x'; + cBase = 16; + cDigitCount = 2; + +function MakeSelection(Index, Digit: Integer): TKHexEditorSelection; +begin + Result.Index := Index; + Result.Digit := Digit; +end; + +function DigitToBin(Value: AnsiChar): Integer; +begin + if ((Value >= 'a') and (Value <= 'f')) then Result := Ord(Value) - Ord('a') + 10 + else if ((Value >= 'A') and (Value <= 'F')) then Result := Ord(Value) - Ord('A') + 10 + else if ((Value >= '0') and (Value <= '9')) then Result := Ord(Value) - Ord('0') + else Result := -1; +end; + +function DigitsToBinStr(var S: AnsiString; Convert: Boolean = True): Boolean; +var + I, J, K: Integer; + T: AnsiString; +begin + // check and convert text characters to hex values 0..15 + Result := True; + if Convert then + SetLength(T, Length(S)); + J := 0; + for I := 1 to Length(S) do if not CharInSetEx(S[I], [#9, #32]) then + begin + K := DigitToBin(S[I]); + if K >= 0 then + begin + if Convert then + begin + Inc(J); + T[J] := AnsiChar(K) + end; + end else + begin + Result := False; + Break; + end; + end; + if Result and Convert then + begin + SetLength(T, J); + S := T; + end; +end; + +function BinStrToBinary(const S: AnsiString): AnsiString; +var + I, J, L: Integer; + B1, B2: Byte; +begin + L := Length(S); + Result := ''; + if L > 0 then + begin + SetLength(Result, DivUp(L, 2)); + if L = 1 then + Result := S + else + begin + J := 1; + for I := 1 to Length(Result) do + begin + B1 := Byte(S[J]); Inc(J); + if J <= L then + begin + B2 := Byte(S[J]); Inc(J); + end else + B2 := 0; + Result[I] := AnsiChar(B1 shl 4 + B2); + end; + end; + end; +end; + +function BinaryToDigits(Buffer: PBytes; SelStart, SelEnd: TKHexEditorSelection): AnsiString; +var + I, J: Integer; + S: AnsiString; +begin + Result := ''; + S := '%s' + cFmtText; + for I := SelStart.Index to SelEnd.Index do + begin + Result := AnsiString(Format(string(S), [Result, Buffer[I]])); + if I = SelStart.Index then + begin + for J := 0 to SelStart.Digit - 1 do + Delete(Result, 1, 1); + end; + if I = SelEnd.Index then + begin + for J := SelEnd.Digit to cDigitCount - 1 do + Delete(Result, Length(Result), 1); + end; + end; +end; + +function BinaryToText(Buffer: PBytes; SelStart, SelEnd: Integer; + CharMapping: PKEditCharMapping): AnsiString; +var + I: Integer; +begin + if SelEnd > SelStart then + begin + SetLength(Result, SelEnd - SelStart); + System.Move(Buffer[SelStart], Result[1], SelEnd - SelStart); + if CharMapping <> nil then + for I := 1 to Length(Result) do + Result[I] := CharMapping^[Byte(Result[I])]; + end else + Result := ''; +end; + +function ReplaceDigit(Value, Digit, Pos: Integer): Integer; +var + I, Mask, O: Integer; +begin + O := 1; + for I := Pos to cDigitCount - 2 do + O := O * cBase; + Mask := cBase - 1; + Result := (((Value div O) and not Mask) + (Digit and Mask)) * O + Value mod O; +end; + +function OppositeReason(ItemReason: TKHexEditorChangeReason): TKHexEditorChangeReason; +begin + case ItemReason of + crDeleteChar: Result := crInsertChar; + crDeleteDigits: Result := crInsertDigits; + crDeleteString: Result := crInsertString; + crInsertChar: Result := crDeleteChar; + crInsertDigits: Result := crDeleteDigits; + crInsertString: Result := crDeleteString; + else + Result := ItemReason; + end; +end; + +{ TKHexEditorColors } + +constructor TKHexEditorColors.Create(AOwner: TKCustomHexEditor); +begin + FOwner := AOwner; + Initialize; + ClearBrightColors; +end; + +procedure TKHexEditorColors.Assign(Source: TPersistent); +begin + if Source is TKHexEditorColors then + begin + Colors := TKHexEditorColors(Source).Colors; + FOwner.Invalidate; + end + else + inherited; +end; + +procedure TKHexEditorColors.ClearBrightColors; +var + I: TKHexEditorColorIndex; +begin + for I := 0 to Length(FBrightColors) - 1 do + FBrightColors[I] := clNone; +end; + +function TKHexEditorColors.GetColor(Index: TKHexEditorColorIndex): TColor; +const + AreaBkGndSet = [ciAddressBkgnd, ciDigitBkGnd, ciTextBkGnd]; + BkGndSet = [ciAddressBkgnd, ciBkGnd, ciDigitBkGnd, ciInactiveCaretBkGnd, + ciInactiveCaretSelBkGnd, ciSelBkGnd, ciSelBkGndFocused, ciTextBkgnd]; +begin + case FColorScheme of + ecsGrayed: if Index in BkGndSet then Result := clWindow else Result := clGrayText; + ecsBright: + begin + if FBrightColors[Index] = clNone then + FBrightColors[Index] := BrightColor(FColors[Index], 0.5, bsOfTop); + if FSingleBkGnd and (Index in AreaBkGndSet) then + Result := FBrightColors[ciBkGnd] + else + Result := FBrightColors[Index]; + end; + ecsGrayScale: Result := ColorToGrayScale(FColors[Index]); + else + if FSingleBkGnd and (Index in AreaBkGndSet) then + Result := FColors[ciBkGnd] + else + Result := FColors[Index]; + end; +end; + +function TKHexEditorColors.GetColorData(Index: TKHexEditorColorIndex): TKHexEditorColorData; +var + ColorSpec: TKHexEditorColorSpec; +begin + Result.Index := Index; + Result.Color := FColors[Index]; + ColorSpec := GetColorSpec(Index); + Result.Default := ColorSpec.Def; + Result.Name := ColorSpec.Name; +end; + +function TKHexEditorColors.GetColorEx(Index: TKHexEditorColorIndex): TColor; +begin + Result := FColors[Index]; +end; + +function TKHexEditorColors.GetColorName(Index: TKHexEditorColorIndex): string; +begin + Result := GetColorSpec(Index).Name; +end; + +procedure TKHexEditorColors.Initialize; +var + I: TKHexEditorColorIndex; +begin + SetLength(FColors, ciHexEditorColorsMax + 1); + SetLength(FBrightColors, ciHexEditorColorsMax + 1); + for I := 0 to Length(FColors) - 1 do + FColors[I] := GetColorSpec(I).Def; +end; + +procedure TKHexEditorColors.SetColor(Index: TKHexEditorColorIndex; Value: TColor); +begin + if FColors[Index] <> Value then + begin + FColors[Index] := Value; + FBrightColors[Index] := clNone; + if not (csLoading in FOwner.ComponentState) and FOwner.HandleAllocated then + FOwner.Invalidate; + end; +end; + +procedure TKHexEditorColors.SetColorEx(Index: TKHexEditorColorIndex; Value: TColor); +begin + if FColors[Index] <> Value then + begin + FColors[Index] := Value; + FBrightColors[Index] := clNone; + end; +end; + +procedure TKHexEditorColors.SetColors(const Value: TKColorArray); +begin + FColors := Value; + ClearBrightColors; +end; + +{ TKHexEditorChangeList } + +constructor TKHexEditorChangeList.Create(AEditor: TKCustomHexEditor; + RedoList: TKHexEditorChangeList); +begin + inherited Create; + FEditor := AEditor; + FGroupUseLock := 0; + FLimit := cUndoLimitDef; + FIndex := -1; + FModifiedIndex := FIndex; + FRedoList := RedoList; + FOnChange := nil; +end; + +procedure TKHexEditorChangeList.AddChange(ItemReason: TKHexEditorChangeReason; + const Data: AnsiString; Inserted: Boolean); +var + P: PKHexEditorChangeItem; +begin + // don't allow succesive crCaretPos + if (ItemReason = crCaretPos) and not Inserted and (FIndex >= 0) and + (PKHexEditorChangeItem(Items[FIndex]).ItemReason = crCaretPos) then + Exit; + if FIndex < FLimit - 1 then + begin + if FIndex < Count - 1 then + Inc(FIndex) + else + FIndex := Add(New(PKHexEditorChangeItem)); + P := Items[FIndex]; + if FGroupUseLock > 0 then + begin + P.Group := FGroup; + P.GroupReason := FGroupReason; + end else + begin + P.Group := 0; + P.GroupReason := ItemReason; + end; + P.ItemReason := ItemReason; + P.EditArea := FEditor.EditArea; + P.SelEnd := FEditor.SelEnd; + P.SelStart := FEditor.SelStart; + P.Data := Data; + P.Inserted := Inserted; + if FRedoList <> nil then + FRedoList.Clear; + if Assigned(FOnChange) then + FOnChange(Self, ItemReason); + end; +end; + +procedure TKHexEditorChangeList.BeginGroup(GroupReason: TKHexEditorChangeReason); +begin + if FGroupUseLock = 0 then + begin + FGroupReason := GroupReason; + Inc(FGroup); + if FGroup = 0 then Inc(FGroup); + end; + Inc(FGroupUseLock); +end; + +function TKHexEditorChangeList.CanPeek: Boolean; +begin + Result := FIndex >= 0; +end; + +procedure TKHexEditorChangeList.Clear; +begin + inherited; + FGroupUseLock := 0; + FIndex := -1; + FModifiedIndex := FIndex; +end; + +procedure TKHexEditorChangeList.EndGroup; +begin + if FGroupUseLock > 0 then + Dec(FGroupUseLock); +end; + +function TKHexEditorChangeList.GetModified: Boolean; + + function CaretPosOnly: Boolean; + var + I: Integer; + begin + Result := True; + for I := FModifiedIndex + 1 to FIndex do + begin + if PKHexEditorChangeItem(Items[I]).ItemReason <> crCaretPos then + begin + Result := False; + Exit; + end; + end; + end; + +begin + Result := (FIndex > FModifiedIndex) and not CaretPosOnly; +end; + +procedure TKHexEditorChangeList.Notify(Ptr: Pointer; Action: TListNotification); +var + P: PKHexEditorChangeItem; +begin + case Action of + lnDeleted: + if Ptr <> nil then + begin + P := Ptr; + Dispose(P); + end; + end; +end; + +function TKHexEditorChangeList.PeekItem: PKHexEditorChangeItem; +begin + if CanPeek then + begin + Result := Items[FIndex]; + Dec(FIndex); + end else + Result := nil; +end; + +procedure TKHexEditorChangeList.PokeItem; +begin + if FIndex < Count - 1 then + Inc(FIndex); +end; + +procedure TKHexEditorChangeList.SetGroupData(Group: Integer; + GroupReason: TKHexEditorChangeReason); +begin + FGroup := Group; + FGroupReason := GroupReason; + FGroupUseLock := 1; +end; + +procedure TKHexEditorChangeList.SetLimit(Value: Integer); +begin + if Value <> FLimit then + begin + FLimit := MinMax(Value, cUndoLimitMin, cUndoLimitMax); + while Count > FLimit do + Delete(0); + FIndex := Min(FIndex, FLimit - 1); + end; +end; + +procedure TKHexEditorChangeList.SetModified(Value: Boolean); +begin + if not Value then + FModifiedIndex := FIndex; +end; + +{ TKCustomHexEditor } + +constructor TKCustomHexEditor.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + Color := clWindow; + ControlStyle := [csOpaque, csClickEvents, csDoubleClicks, csCaptureMouse]; + Font.Name := cFontNameDef; + Font.Style := cFontStyleDef; + Font.Size := cFontSizeDef; + Font.Pitch := fpFixed; + Font.OnChange := FontChange; + Height := cHeight; + ParentColor := False; + ParentFont := False; + TabStop := True; + Width := cWidth; + FAddressCursor := cAddressCursorDef; + FAddressMode := cAddressModeDef; + FAddressOffset := cAddressOffsetDef; + FAddressPrefix := cAddressPrefixDef; + FAddressSize := cAddressSizeDef; + FAreaSpacing := cAreaSpacingDef; + FBuffer := nil; +{$IFNDEF FPC} + FClipBoardFormat := RegisterClipboardFormat('Any binary data'); +{$ENDIF} + FColors := TKHexEditorColors.Create(Self); + FCharHeight := 8; + FCharMapping := DefaultCharMapping; + FCharSpacing := cCharSpacingDef; + FCharWidth := 6; + FDigitGrouping := cDigitGroupingDef; + FDisabledDrawStyle := cDisabledDrawStyleDef; + FDrawStyles := cDrawStylesDef; + FEditArea := eaDigits; + FLeftChar := 0; + FLineHeightPercent := cLineHeightPercentDef; + FLineSize := cLineSizeDef; + FMouseWheelAccumulator := 0; + FOptions := [eoGroupUndo]; + FKeyMapping := CreateDefaultKeyMapping; + FRedoList := TKHexEditorChangeList.Create(Self, nil); + FScrollBars := ssBoth; + FScrollSpeed := cScrollSpeedDef; + FScrollTimer := TTimer.Create(Self); + FScrollTimer.Enabled := False; + FScrollTimer.Interval := FScrollSpeed; + FScrollTimer.OnTimer := ScrollTimerHandler; + FSelStart := MakeSelection(0, 0); + FSelEnd := MakeSelection(0, 0); + FStates := []; + FTopLine := 0; + FTotalCharSpacing := 0; + FUndoList := TKHexEditorChangeList.Create(Self, FRedoList); + FUndoList.OnChange := UndoChange; + FOnChange := nil; + FOnReplaceText := nil; + UpdateCharMetrics; +end; + +destructor TKCustomHexEditor.Destroy; +begin + inherited; + FOnChange := nil; + FColors.Free; + FUndoList.Free; + FRedoList.Free; + FreeMem(FBuffer); + FBuffer := nil; +end; + +procedure TKCustomHexEditor.AddUndoCaretPos(Force: Boolean); +begin + FUndoList.AddChange(crCaretPos, '', Force); +end; + +procedure TKCustomHexEditor.AddUndoByte(ItemReason: TKHexEditorChangeReason; Data: Byte; + Inserted: Boolean = True); +begin + FUndoList.AddChange(ItemReason, AnsiChar(Data), Inserted); +end; + +procedure TKCustomHexEditor.AddUndoBytes(ItemReason: TKHexEditorChangeReason; + Data: PBytes; Length: Integer; Inserted: Boolean = True); +var + S: AnsiString; +begin + if Length > 0 then + begin + SetLength(S, Length); + Move(Data^, S[1], Length); + FUndoList.AddChange(ItemReason, S, Inserted); + end; +end; + +procedure TKCustomHexEditor.AddUndoString(ItemReason: TKHexEditorChangeReason; + const S: AnsiString; Inserted: Boolean = True); +begin + if S <> '' then + FUndoList.AddChange(ItemReason, S, Inserted); +end; + +procedure TKCustomHexEditor.Append(At: Integer; Data: TDataSize); +var + S: AnsiString; +begin + if (Data.Size > 0) and (Data.Data <> nil) then + begin + SetString(S, PAnsiChar(Data.Data), Data.Size); + InsertString(At, S, Data.Size); + end; +end; + +procedure TKCustomHexEditor.Append(At: Integer; const Data: AnsiString); +begin + InsertString(At, Data, Length(Data)); +end; + +procedure TKCustomHexEditor.Assign(Source: TPersistent); +begin + if Source is TKCustomHexEditor then with Source as TKCustomHexEditor do + begin + Self.AddressCursor := AddressCursor; + Self.AddressMode := AddressMode; + Self.AddressPrefix := AddressPrefix; + Self.AddressSize := AddressSize; + Self.Align := Align; + Self.Anchors := Anchors; + Self.AutoSize := AutoSize; + Self.BiDiMode := BiDiMode; + Self.BorderStyle := BorderStyle; + Self.BorderWidth := BorderWidth; + Self.CharSpacing := CharSpacing; + Self.Color := Color; + Self.Colors := Colors; + Self.Constraints.Assign(Constraints); + {$IFNDEF FPC} + Self.Ctl3D := Ctl3D; + {$ENDIF} + Self.Data := Data; + Self.DigitGrouping := DigitGrouping; + Self.DisabledDrawStyle := DisabledDrawStyle; + Self.DragCursor := DragCursor; + Self.DragKind := DragKind; + Self.DragMode := DragMode; + Self.DrawStyles := DrawStyles; + Self.EditArea := EditArea; + Self.Enabled := Enabled; + Self.Font := Font; + {$IFNDEF FPC} + Self.ImeMode := ImeMode; + Self.ImeName := ImeName; + {$ENDIF} + Self.LineHeightPercent := LineHeightPercent; + Self.LineSize := LineSize; + Self.Modified := False; + Self.Options := Options; + Self.ParentBiDiMode := ParentBiDiMode; + Self.ParentColor := ParentColor; + {$IFNDEF FPC} + Self.ParentCtl3D := ParentCtl3D; + {$ENDIF} + Self.ParentFont := ParentFont; + Self.ParentShowHint := ParentShowHint; + Self.PopupMenu := PopupMenu; + Self.ScrollBars := ScrollBars; + Self.SelEnd := SelEnd; + Self.SelStart := SelStart; + Self.SetCharMapping(GetCharMapping); + Self.SetKeyMapping(GetKeyMapping); + Self.ShowHint := ShowHint; + Self.TabOrder := TabOrder; + Self.TabStop := TabStop; + Self.Visible := Visible; + end + else + inherited; +end; + +procedure TKCustomHexEditor.BeginUndoGroup(GroupReason: TKHexEditorChangeReason); +begin + FUndoList.BeginGroup(GroupReason); +end; + +procedure TKCustomHexEditor.BufferChanged; +begin + FUndoList.Clear; + FRedoList.Clear; + UpdateScrollRange; + SelectionChanged(False); + DoChange; +end; + +function TKCustomHexEditor.CanScroll(Command: TKEditCommand): Boolean; +var + XMax, YMax: Integer; + P: TPoint; + AD: TKHExEditorAreaDimensions; +begin + AD := GetAreaDimensions; + XMax := GetMaxLeftChar(AD.TotalHorz); + YMax := GetMaxTopLine(AD.TotalVert); + case Command of + ecScrollUp: Result := FTopLine > 0; + ecScrollDown: Result := FTopLine < YMax; + ecScrollLeft: Result := FLeftChar > 0; + ecScrollRight: Result := FLeftChar < XMax; + ecScrollCenter: + begin + P := SelToPoint(FSelEnd, FEditArea); + P.X := P.X - ClientWidth div 2; + P.Y := P.Y - ClientHeight div 2; + Result := (FLeftChar > 0) and (P.X < 0) or (FLeftChar < XMax) and (P.X > FCharWidth) or + (FTopLine > 0) and (P.Y < 0) or (FTopLine < YMax) and (P.Y > FCharHeight); + end; + else + Result := False; + end; +end; + +function TKCustomHexEditor.CaretInView: Boolean; +begin + Result := PtInRect(GetModifiedClientRect, SelToPoint(FSelEnd, FEditArea)); +end; + +procedure TKCustomHexEditor.Clear; +begin + if FBuffer <> nil then + begin + FreeMem(FBuffer); + FBuffer := nil; + FSize := 0; + BufferChanged; + end; +end; + +procedure TKCustomHexEditor.ClearChar(At: Integer); +begin + ClearString(At, 1); +end; + +procedure TKCustomHexEditor.ClearDigitSelection; +begin + FSelStart.Digit := 0; + FSelEnd.Digit := 0; +end; + +procedure TKCustomHexEditor.ClearString(At, Size: Integer); +begin + if (FBuffer <> nil) and (Size > 0) and (At >= 0) and (At + Size <= FSize) then + begin + Move(FBuffer[At + Size], FBuffer[At], (FSize - At - Size) * SizeOf(Byte)); + Dec(FSize, Size); + ReallocMem(FBuffer, FSize); + UpdateScrollRange; + Invalidate; + end; +end; + +procedure TKCustomHexEditor.ClearUndo; +begin + FUndoList.Clear; + FRedoList.Clear; +end; + +procedure TKCustomHexEditor.CMEnabledChanged(var Msg: TLMessage); +begin + inherited; + UpdateEditorCaret; + Invalidate; +end; + +procedure TKCustomHexEditor.CMSysColorChange(var Msg: TLMessage); +begin + inherited; + FColors.ClearBrightColors; +end; + +function TKCustomHexEditor.CommandEnabled(Command: TKEditCommand): Boolean; +var + L: TKHexEditorSelection; +begin + if Enabled and Visible and not (csDesigning in ComponentState) then + begin + L := SelLength; + case Command of + // movement commands + ecLeft, ecSelLeft: Result := (FSelEnd.Index > 0) or (FEditArea = eaDigits) and (FSelEnd.Digit > 0); + ecRight, ecSelRight: Result := (FEditArea <> eaNone) and (FSelEnd.Index < FSize); + ecUp, ecSelUp: Result := FSelEnd.Index >= FLineSize; + ecDown, ecSelDown: Result := (FEditArea <> eaNone) and (FSelEnd.Index < FSize); + ecLineStart, ecSelLineStart: Result := (FEditArea <> eaNone) and (FSelEnd.Index mod FLineSize > 0); + ecLineEnd, ecSelLineEnd: Result := (FEditArea <> eaNone) and (FSelEnd.Index mod FLineSize < Min(FLineSize - 1, FSize)); + ecPageUp, ecSelPageUp: Result := FSelEnd.Index >= FlineSize; + ecPageDown, ecSelPageDown: Result := (FEditArea <> eaNone) and (FSelEnd.Index < FSize div FLineSize * FLineSize); + ecPageLeft, ecSelPageLeft: Result := (FEditArea <> eaNone) and (GetPageHorz > 0) and (FSelEnd.Index mod FLineSize > 0); + ecPageRight, ecSelPageRight: Result := (FEditArea <> eaNone) and (GetPageHorz > 0) and (FSelEnd.Index mod FLineSize < Min(FLineSize - 1, FSize)); + ecPageTop, ecSelPageTop: Result := (FEditArea <> eaNone) and (FSelEnd.Index > 0) and (SelToPoint(MakeSelection(FSelEnd.Index, 0), FEditArea).Y div FCharHeight <> 0); + ecPageBottom, ecSelPageBottom: Result := (FEditArea <> eaNone) and (FSelEnd.Index < FSize) and ((ClientHeight - SelToPoint(MakeSelection(FSelEnd.Index, 0), FEditArea).Y) div FCharHeight - 1 <> 0); + ecEditorTop, ecSelEditorTop: Result := FSelEnd.Index > 0; + ecEditorBottom, ecSelEditorBottom: Result := (FEditArea <> eaNone) and (FSelEnd.Index < FSize); + ecGotoXY, ecSelGotoXY: Result := True; + // scroll commands + ecScrollUp, ecScrollDown, ecScrollLeft, ecScrollRight, ecScrollCenter: Result := CanScroll(Command); + // editing commands + ecUndo: Result := not ReadOnly and FUndoList.CanPeek; + ecRedo: Result := not ReadOnly and FRedoList.CanPeek; + ecCopy, ecCut: Result := not Empty and (not ReadOnly or (Command = ecCopy)) and ((L.Index <> 0) or (L.Digit <> 0)); + ecPaste: Result := not ReadOnly and (FEditArea <> eaNone) and (ClipBoard.FormatCount > 0); + ecInsertChar: Result := not ReadOnly and (FEditArea <> eaNone); + ecInsertDigits: Result := not ReadOnly and (FEditArea = eaDigits); + ecInsertString: Result := not ReadOnly and (FEditArea <> eaNone); + ecDeleteLastChar: Result := not (Empty or ReadOnly) and (FEditArea <> eaNone) and ((L.Index > 0) or (FSelEnd.Index > 0)); + ecDeleteChar: Result := not (Empty or ReadOnly) and (FEditArea <> eaNone) and ((L.Index > 0) or (FSelEnd.Index < FSize)); + ecDeleteBOL: Result := not (Empty or ReadOnly) and (FEditArea <> eaNone) and ((L.Index > 0) or (FSelEnd.Index mod FLineSize > 0)); + ecDeleteEOL: Result := not (Empty or ReadOnly) and (FEditArea <> eaNone) and ((L.Index > 0) or (FSelEnd.Index mod FLineSize < Min(FLineSize, FSize))); + ecDeleteLine: Result := not (Empty or ReadOnly) and (FEditArea <> eaNone) and ((L.Index > 0) or (FSelEnd.Index mod FLineSize > 0) or (FSelEnd.Index < FSize)); + ecSelectAll: Result := not (Empty or ReadOnly) and (FEditArea <> eaNone); + ecClearAll: Result := not (Empty or ReadOnly) and (FEditArea <> eaNone); + ecClearIndexSelection, ecClearSelection: Result := not (Empty or ReadOnly) and (FEditArea <> eaNone) and (L.Index > 0); + ecSearch: Result := not Empty; + ecReplace: Result := not (Empty or ReadOnly); + ecInsertMode: Result := elOverwrite in FStates; + ecOverwriteMode: Result := not (elOverwrite in FStates); + else + Result := True; + end; + end else + Result := False; +end; + +procedure TKCustomHexEditor.CreateParams(var Params: TCreateParams); +begin + inherited; + with Params do + begin + if FScrollBars in [ssVertical, ssBoth] then Style := Style or WS_VSCROLL; + if FScrollBars in [ssHorizontal, ssBoth] then Style := Style or WS_HSCROLL; + end; +end; + +procedure TKCustomHexEditor.CreateWnd; +begin + inherited; +{$IFDEF USE_WINAPI} + if (eoDropFiles in FOptions) and not (csDesigning in ComponentState) then + DragAcceptFiles(Handle, TRUE); +{$ENDIF} +end; + +procedure TKCustomHexEditor.DestroyWnd; +begin +{$IFDEF USE_WINAPI} + if (eoDropFiles in FOptions) and not (csDesigning in ComponentState) then + DragAcceptFiles(Handle, FALSE); +{$ENDIF} + inherited; +end; + +procedure TKCustomHexEditor.DoChange; +begin + if Assigned(FOnChange) then + FOnChange(Self); +end; + +function TKCustomHexEditor.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; + MousePos: TPoint): Boolean; +const + WHEEL_DIVISOR = 120; +var + LinesToScroll, WheelClicks: Integer; +begin + Result := inherited DoMouseWheel(Shift, WheelDelta, MousePos); + if not Result then + begin + if ssCtrl in Shift then + LinesToScroll := GetModifiedClientRect.Bottom div FCharHeight + else + LinesToScroll := 3; + Inc(FMouseWheelAccumulator, WheelDelta); + WheelClicks := FMouseWheelAccumulator div WHEEL_DIVISOR; + FMouseWheelAccumulator := FMouseWheelAccumulator mod WHEEL_DIVISOR; + ScrollBy(0, - WheelClicks * LinesToScroll, True); + Result := True; + end; +end; + +procedure TKCustomHexEditor.EditAreaChanged; +begin + if FEditArea = eaNone then + FEditArea := eaDigits; + if not (edAddress in FDrawStyles) and (FEditArea = eaAddress) then + FEditArea := eaDigits; + if not (edDigits in FDrawStyles) and (FEditArea = eaDigits) then + FEditArea := eaText; + if not (edText in FDrawStyles) and (FEditArea = eaText) then + if edDigits in FDrawStyles then + FEditArea := eaDigits + else + FEditArea := eaNone; +end; + +procedure TKCustomHexEditor.EndUndoGroup; +begin + FUndoList.EndGroup; +end; + +function TKCustomHexEditor.ExecuteCommand(Command: TKEditCommand; + Data: Pointer): Boolean; +var + I, J, K, M, N, O: Integer; + CanInsert, MoreBytes, Found, MatchCase: Boolean; + C1, C2, C3: AnsiChar; + S, S_FirstChar, S_LastChar, T: AnsiString; + P: TPoint; + Area: TKHexEditorArea; + L, OldSelStart, OldSelEnd, Sel1, Sel2: TKHexEditorSelection; + PChI, PChI_First, PChI_Next: PKHexEditorChangeItem; + PSD: PKEditSearchData; + ReplaceAction: TKEditReplaceAction; +{$IFNDEF FPC} + BA: PBytes; + H: THandle; +{$ENDIF} +begin + Result := False; + if CommandEnabled(Command) then + begin + Result := True; + L := SelLength; + OldSelEnd := FSelEnd; + OldSelStart := FSelStart; + case Command of + ecLeft..ecSelGotoXY: AddUndoCaretPos(False); + end; + case Command of + ecLeft, ecSelLeft: + begin + InternalMoveLeft; + SelectionChanged(Command <> ecSelLeft); + end; + ecRight, ecSelRight: + begin + InternalMoveRight; + SelectionChanged(Command <> ecSelRight); + end; + ecUp, ecSelUp: + begin + Dec(FSelEnd.Index, FLineSize); + SelectionChanged(Command <> ecSelUp); + end; + ecDown, ecSelDown: + begin + Inc(FSelEnd.Index, FLineSize); + SelectionChanged(Command <> ecSelDown); + end; + ecLineStart, ecSelLineStart: + begin + FSelEnd := MakeSelection((FSelEnd.Index div FLineSize) * FLineSize, 0); + SelectionChanged(Command <> ecSelLineStart); + end; + ecLineEnd, ecSelLineEnd: + begin + FSelEnd := MakeSelection((FSelEnd.Index div FLineSize) * FLineSize + FLineSize - 1, cDigitCount - 1); + SelectionChanged(Command <> ecSelLineEnd); + end; + ecPageUp, ecSelPageUp: + begin + Dec(FSelEnd.Index, Min(ClientHeight div FCharHeight, FSelEnd.Index div FLineSize) * FLineSize); + SelectionChanged(Command <> ecSelPageUp); + end; + ecPageDown, ecSelPageDown: + begin + Inc(FSelEnd.Index, Min(ClientHeight div FCharHeight, (FSize - FSelEnd.Index) div FLineSize) * FLineSize); + SelectionChanged(Command <> ecSelPageDown); + end; + ecPageLeft, ecSelPageLeft: + begin + Dec(FSelEnd.Index, Min(GetPageHorz, FSelEnd.Index mod FLineSize)); + SelectionChanged(Command <> ecSelPageLeft); + end; + ecPageRight, ecSelPageRight: + begin + Inc(FSelEnd.Index, Min(GetPageHorz, FLineSize - 1 - FSelEnd.Index mod FLineSize)); + SelectionChanged(Command <> ecSelPageRight); + end; + ecPageTop, ecSelPageTop: + begin + P := SelToPoint(MakeSelection(FSelEnd.Index, 0), FEditArea); + Dec(FSelEnd.Index, P.Y div FCharHeight * FLineSize); + SelectionChanged(Command <> ecSelPageTop); + end; + ecPageBottom, ecSelPageBottom: + begin + P := SelToPoint(MakeSelection(FSelEnd.Index, 0), FEditArea); + Inc(FSelEnd.Index, ((ClientHeight - P.Y) div FCharHeight - 1) * FLineSize); + SelectionChanged(Command <> ecSelPageBottom); + end; + ecEditorTop, ecSelEditorTop: + begin + FSelEnd := MakeSelection(0, 0); + SelectionChanged(Command <> ecSelEditorTop); + end; + ecEditorBottom, ecSelEditorBottom: + begin + FSelEnd := MakeSelection(FSize, 0); + SelectionChanged(Command <> ecSelEditorBottom); + end; + ecGotoXY, ecSelGotoXY: + begin + Sel1 := PointToSel(PPoint(Data)^, False, Area); + if Area <> eaNone then + begin + FSelEnd := Sel1; + FEditArea := Area; + SelectionChanged(Command <> ecSelGotoXY); + end else + Result := False; + end; + // scroll commands + ecScrollUp: + begin + if (FEditArea <> eaNone) and (SelToPoint(FSelEnd, FEditArea).Y >= GetModifiedClientRect.Bottom - FCharHeight) then + begin + ScrollBy(0, -1, False); + Dec(FSelEnd.Index, FLineSize); + SelectionChanged(True, False); + Invalidate; + end else + ScrollBy(0, -1, True); + end; + ecScrollDown: + begin + if (FEditArea <> eaNone) and (SelToPoint(FSelEnd, FEditArea).Y <= GetModifiedClientRect.Top) then + begin + ScrollBy(0, 1, False); + Inc(FSelEnd.Index, FLineSize); + SelectionChanged(True, False); + Invalidate; + end else + ScrollBy(0, 1, True); + end; + ecScrollLeft: + begin + if FEditArea <> eaNone then + begin + // overscroll check + P := SelToPoint(MakeSelection(0, 0), FEditArea); + if P.X < GetModifiedClientRect.Right - FCharWidth then + begin + ScrollBy(-1, 0, True); + P := SelToPoint(FSelEnd, FEditArea); + if (P.X >= GetModifiedClientRect.Right) and ((FSelEnd.Index mod FLineSize > 0) or (FSelEnd.Digit > 0)) then + ExecuteCommand(ecLeft) + end; + end else + ScrollBy(-1, 0, True); + end; + ecScrollRight: + begin + if FEditArea <> eaNone then + begin + // overscroll check + P := SelToPoint(MakeSelection(FLineSize - 1, cDigitCount - 1), FEditArea); + if P.X > 0 then + begin + ScrollBy(1, 0, True); + P := SelToPoint(FSelEnd, FEditArea); + if (P.X < 0) and ((FSelEnd.Index mod FLineSize < FLineSize - 1) or (FSelEnd.Digit < cDigitCount - 1)) then + ExecuteCommand(ecRight) + end; + end else + ScrollBy(1, 0, True); + end; + ecScrollCenter: + begin + P := SelToPoint(FSelEnd, FEditArea); + I := (P.X - ClientWidth div 2) div FCharWidth; + J := (P.Y - ClientHeight div 2) div FCharHeight; + ScrollBy(I, J, True); + end; + // editing commands + ecUndo: + begin + PChI := FUndoList.PeekItem; + PChI_First := PChI; + while PChI <> nil do + begin + I := Length(PChI.Data); + J := Min(I, FSize - PChI.SelEnd.Index); + FRedoList.SetGroupData(PChI.Group, PChI.GroupReason); + case PChI.ItemReason of + crCaretPos: + FRedoList.AddChange(crCaretPos, ''); + crDeleteChar, crDeleteDigits, crDeleteString: + begin + if FBuffer <> nil then + begin + SetLength(S, J); + System.Move(FBuffer[PChI.SelEnd.Index], S[1], J); + end else + S := ''; + FRedoList.AddChange(OppositeReason(PChI.ItemReason), S, PChI.Inserted); + end; + crInsertChar, crInsertDigits, crInsertString: + FRedoList.AddChange(OppositeReason(PChI.ItemReason), PChI.Data); + end; + FSelEnd := PChI.SelEnd; + FSelStart := PChI.SelStart; + FEditArea := PChI.EditArea; + case PChI.ItemReason of + crDeleteChar, crDeleteDigits, crDeleteString: + begin + if PChI.Inserted then + ClearString(PChI.SelEnd.Index, I) + else if FBuffer <> nil then + begin + System.Move(PChI.Data[1], FBuffer[PChI.SelEnd.Index], J); + Invalidate; + end; + end; + crInsertChar, crInsertDigits, crInsertString: + InsertString(GetRealSelStart.Index, PChI.Data, I); + end; + EditAreaChanged; + SelectionChanged(False, False); + if PChI.ItemReason <> crCaretPos then + DoChange; + PChI_Next := FUndoList.PeekItem; + if (PChI_Next <> nil) and not ((PChI.Group <> 0) and (PChI.Group = PChI_Next.Group) or + (eoGroupUndo in FOptions) and (PChI_First.GroupReason = PChI_Next.GroupReason)) then + begin + FUndoList.PokeItem; + Break; + end; + PChI := PChI_Next; + end; + if not CaretInView then + ExecuteCommand(ecScrollCenter); + end; + ecRedo: + begin + PChI := FRedoList.PeekItem; + PChI_First := PChI; + while PChI <> nil do + begin + FUndoList.PokeItem; + I := Length(PChI.Data); + Sel1 := GetRealSelStart; + case PChI.ItemReason of + crInsertChar, crInsertDigits, crInsertString: + begin + if PChI.Inserted then + InsertString(Sel1.Index, PChI.Data, I) + else if FBuffer <> nil then + begin + System.Move(PChI.Data[1], FBuffer[Sel1.Index], Min(I, FSize - FSelEnd.Index)); + Invalidate; + end; + end; + crDeleteChar, crDeleteDigits, crDeleteString: + ClearString(Sel1.Index, I); + end; + FSelEnd := PChI.SelEnd; + FSelStart := PChI.SelStart; + FEditArea := PChI.EditArea; + EditAreaChanged; + SelectionChanged(False, False); + if PChI.ItemReason <> crCaretPos then + DoChange; + PChI_Next := FRedoList.PeekItem; + if (PChI_Next <> nil) and not ((PChI.Group <> 0) and (PChI.Group = PChI_Next.Group) or + (eoGroupUndo in FOptions) and (PChI_First.GroupReason = PChI_Next.GroupReason)) then + begin + FRedoList.PokeItem; + Break; + end; + PChI := PChI_Next; + end; + if not CaretInView then + ExecuteCommand(ecScrollCenter); + end; + ecCopy: + begin + Sel1 := GetRealSelStart; + Sel2 := GetRealSelEnd; + {$IFDEF FPC} + ClipBoard.AsText := string(BinaryToDigits(FBuffer, Sel1, Sel2)) + {$ELSE} + if FEditArea = eaDigits then + ClipBoard.AsText := string(BinaryToDigits(FBuffer, Sel1, Sel2)) + else if L.Index <> 0 then + begin + S := BinaryToText(FBuffer, Sel1.Index, Sel2.Index, @FCharMapping); + H := GlobalAlloc(GMEM_MOVEABLE + GMEM_DDESHARE, L.Index); + try + BA := GlobalLock(H); + try + System.Move(FBuffer[Sel1.Index], BA^, L.Index); + finally + GlobalUnlock(H); + end; + ClipBoard.Open; + try + ClipBoard.SetAsHandle(FClipboardFormat, H); + ClipBoard.AsText := string(S); + finally + ClipBoard.Close; + end; + except + GlobalFree(H); + end; + end; + {$ENDIF} + end; + ecCut: + begin + ExecuteCommand(ecCopy); + ExecuteCommand(ecClearSelection); + end; + ecPaste: + begin + if L.Index > 0 then + ExecuteCommand(ecClearSelection); + if ClipBoard.FormatCount > 0 then + begin + S := ''; + {$IFNDEF FPC} + H := 0; + // paste as binary data + if ClipBoard.HasFormat(FClipboardFormat) then + H := ClipBoard.GetAsHandle(FClipboardFormat) else + {$ENDIF} + if ClipBoard.HasFormat(CF_TEXT) then + begin + S := AnsiString(ClipBoard.AsText); + if S <> '' then + begin + M := Length(S); + if (FEditArea = eaDigits) and ExecuteCommand(ecInsertDigits, Pointer(S)) then + begin + S := ''; + if M >= cDigitCount then + begin + Inc(FSelEnd.Index, M div cDigitCount) + end else + begin + Inc(FSelEnd.Digit, M); + if FSelEnd.Digit >= cDigitCount then + begin + Inc(FSelEnd.Index); + FSelEnd.Digit := FSelEnd.Digit mod cDigitCount; + end; + end; + SelectionChanged(True); + end else + ExecuteCommand(ecInsertString, Pointer(S)); + end; + end + {$IFNDEF FPC} + else + H := ClipBoard.GetAsHandle(ClipBoard.Formats[0]); + if H <> 0 then + begin + BA := GlobalLock(H); + try + I := GlobalSize(H); + if I > 0 then + begin + SetLength(S, I); + System.Move(BA^, S[1], I); + end; + finally + GlobalUnlock(H); + end; + if S <> '' then + ExecuteCommand(ecInsertString, Pointer(S)); + end + {$ENDIF} + ; + if S <> '' then + begin + Inc(FSelEnd.Index, Length(S)); + FSelEnd.Digit := 0; + SelectionChanged(True); + end; + end; + end; + ecInsertChar: + begin + BeginUndoGroup(crInsertChar); + try + N := PByte(Data)^; + if L.Index > 0 then + ExecuteCommand(ecClearSelection); + ValidateSelection(FSelEnd, FEditArea); + if FBuffer <> nil then + I := FBuffer[FSelEnd.Index] + else + I := 0; + CanInsert := (FBuffer = nil) or (FSelEnd.Digit = 0) and + (not (elOverwrite in FStates) or (FSelEnd.Index = FSize)); + AddUndoByte(crDeleteChar, I, CanInsert); + if CanInsert then + InsertChar(FSelEnd.Index, 0) + else + Invalidate; + case FEditArea of + eaDigits: + begin + FBuffer[FSelEnd.Index] := ReplaceDigit(FBuffer[FSelEnd.Index], N, FSelEnd.Digit); + InternalMoveRight; + end; + eaText: + begin + FBuffer[FSelEnd.Index] := N; + InternalMoveRight; + end; + end; + SelectionChanged(True); + finally + EndUndoGroup; + end; + end; + ecInsertDigits: + begin + S := AnsiString(Data); + if (S <> '') and DigitsToBinStr(S) then + begin + BeginUndoGroup(crInsertDigits); + try + if L.Index > 0 then + ExecuteCommand(ecClearSelection); + ValidateSelection(FSelEnd, FEditArea); + MoreBytes := Length(S) >= cDigitCount; + if MoreBytes then + // we don't move digit positions of the remaining block + SetLength(S, Length(S) div cDigitCount * cDigitCount); + J := 0; + if (FBuffer <> nil) and (not MoreBytes or (FSelEnd.Digit > 0)) then + begin + I := FBuffer[FSelEnd.Index]; + S_FirstChar := AnsiChar(I); + S_LastChar := S_FirstChar; + // split current byte + AddUndoByte(crInsertChar, I); + ClearChar(FSelEnd.Index); + N := Length(S); + for I := FSelEnd.Digit to cDigitCount - 1 do + begin + if J < N then + begin + Inc(J); + S_FirstChar := AnsiChar(ReplaceDigit(Ord(S_FirstChar[1]), Ord(S[J]), I)); + end else + Break; + end; + K := Length(S); + if K > J then + for I := FSelEnd.Digit - 1 downto 0 do + begin + if K > J then + begin + S_LastChar := AnsiChar(ReplaceDigit(Ord(S_LastChar[1]), Ord(S[K]), I)); + Dec(K); + end else + Break; + end + else + S_LastChar := ''; + O := cDigitCount; + end else + begin + S_FirstChar := ''; + S_LastChar := ''; + O := 0; + end; + T := ''; + if MoreBytes then + begin + N := Length(S) - O; + O := J; + for I := 0 to N div cDigitCount - 1 do + begin + K := 0; + for J := 1 to cDigitCount do + begin + K := K * cBase; + M := I * 2 + J + O; + Inc(K, Ord(S[M])); + end; + T := AnsiString(Format('%s%s', [T, Char(K)])); + end; + end; + S := S_FirstChar + T + S_LastChar; + // always insert (don't overwrite) + AddUndoString(crDeleteDigits, S); + InsertString(FSelEnd.Index, S, Length(S)); + SelectionChanged(True); + finally + EndUndoGroup; + end; + end else + Result := False; + end; + ecInsertString: + begin + S := AnsiString(Data); + if S <> '' then + begin + BeginUndoGroup(crInsertString); + try + if L.Index > 0 then + ExecuteCommand(ecClearIndexSelection); + // always insert (don't overwrite) + AddUndoString(crDeleteString, S); + InsertString(FSelEnd.Index, S, Length(S)); + SelectionChanged(True); + finally + EndUndoGroup; + end; + end else + Result := False; + end; + ecDeleteLastChar: + begin + if L.Index <> 0 then ExecuteCommand(ecClearSelection) else + begin + BeginUndoGroup(crDeleteString); + try + AddUndoCaretPos; + FSelStart.Index := FSelEnd.Index - 1; + ExecuteCommand(ecClearIndexSelection) + finally + EndUndoGroup; + end; + end; + end; + ecDeleteChar: + begin + if L.Index <> 0 then ExecuteCommand(ecClearSelection) else + begin + BeginUndoGroup(crDeleteString); + try + AddUndoCaretPos; + FSelStart.Index := FSelEnd.Index + 1; + ExecuteCommand(ecClearIndexSelection) + finally + EndUndoGroup; + end; + end; + end; + ecDeleteBOL: + begin + if L.Index <> 0 then ExecuteCommand(ecClearSelection) else + begin + BeginUndoGroup(crDeleteString); + try + AddUndoCaretPos; + FSelStart.Index := (FSelEnd.Index div FLineSize) * FLineSize; + ExecuteCommand(ecClearIndexSelection) + finally + EndUndoGroup; + end; + end; + end; + ecDeleteEOL: + begin + if L.Index <> 0 then ExecuteCommand(ecClearSelection) else + begin + BeginUndoGroup(crDeleteString); + try + AddUndoCaretPos; + FSelStart.Index := Min((FSelEnd.Index div FLineSize + 1) * FLineSize, FSize); + ExecuteCommand(ecClearIndexSelection) + finally + EndUndoGroup; + end; + end; + end; + ecDeleteLine: + begin + if L.Index <> 0 then ExecuteCommand(ecClearSelection) else + begin + BeginUndoGroup(crDeleteString); + try + AddUndoCaretPos; + FSelStart.Index := (FSelEnd.Index div FLineSize) * FLineSize; + FSelEnd.Index := Min(FSelStart.Index + FLineSize, FSize); + ExecuteCommand(ecClearIndexSelection) + finally + EndUndoGroup; + end; + end; + end; + ecSelectAll: + begin + AddUndoCaretPos; + FSelStart := MakeSelection(0, 0); + FSelEnd := MakeSelection(FSize, 0); + SelectionChanged(False); + end; + ecClearAll: + begin + ExecuteCommand(ecSelectAll); + ExecuteCommand(ecClearIndexSelection); + end; + ecClearIndexSelection: + begin + I := GetRealSelStart.Index; + AddUndoBytes(crInsertString, PBytes(@FBuffer[I]), L.Index, True); + ClearString(I, L.Index); + FSelEnd := MakeSelection(I, 0); + SelectionChanged(True); + end; + ecClearSelection: + begin + Sel1 := GetRealSelStart; + Sel2 := GetRealSelEnd; + if (Sel1.Digit > 0) {and (Sel1.Digit + Sel2.Digit = cDigitCount) }then + begin + BeginUndoGroup(crDeleteDigits); + try + // digit clear mode + AddUndoCaretPos; + FSelEnd := MakeSelection(Sel1.Index + 1, 0); + FSelStart := FSelEnd; + if Sel2.Digit = 0 then + begin + Dec(L.Index); + N := FBuffer[Sel2.Index - 1]; + end else + N := FBuffer[Sel2.Index]; + AddUndoBytes(crInsertDigits, PBytes(@FBuffer[FSelEnd.Index]), L.Index, True); + ClearString(FSelEnd.Index, L.Index); + FSelEnd := Sel1; + AddUndoByte(crDeleteChar, FBuffer[Sel1.Index], False); + for I := Sel1.Digit to cDigitCount - 1 do + begin + FBuffer[Sel1.Index] := ReplaceDigit(FBuffer[Sel1.Index], N mod cBase, I); + N := N div cBase; + end; + SelectionChanged(True); + finally + EndUndoGroup; + end; + end else + ExecuteCommand(ecClearIndexSelection); + end; + ecSearch, ecReplace: + begin + // doesn't search for single digits + PSD := Data; + if PSD <> nil then + begin + PSD.ErrorReason := eseOk; + S := AnsiString(PSD.TextToFind); + if Command = ecReplace then + begin + T := AnsiString(PSD.TextToReplace); + ReplaceAction := eraYes; + end; + if esoSelectedOnly in PSD.Options then + if esoFirstSearch in PSD.Options then + begin + PSD.SelStart := GetRealSelStart.Index; + PSD.SelEnd := GetRealSelEnd.Index; + end else + begin + PSD.SelStart := MinMax(PSD.SelStart, 0, FSize); + PSD.SelEnd := MinMax(PSD.SelEnd, 0, FSize); + end; + if esoFirstSearch in PSD.Options then + Exclude(PSD.Options, esoWereDigits); + if esoTreatAsDigits in PSD.Options then + begin + if DigitsToBinStr(S) then + begin + S := BinStrToBinary(S); + if Command = ecReplace then + begin + if DigitsToBinStr(T) then + begin + T := BinStrToBinary(T); + PSD.TextToFind := string(S); + PSD.TextToReplace := string(T); + Exclude(PSD.Options, esoTreatAsDigits); + Include(PSD.Options, esoWereDigits); + end else + PSD.ErrorReason := eseNoDigitsReplace; + end else + begin + PSD.TextToFind := string(S); + Exclude(PSD.Options, esoTreatAsDigits); + Include(PSD.Options, esoWereDigits); + end; + end else + PSD.ErrorReason := eseNoDigitsFind; + end; + if PSD.ErrorReason = eseOk then + begin + N := Length(S); + if esoBackwards in PSD.Options then + begin + O := -1; + if (esoEntireScope in PSD.Options) and (esoFirstSearch in PSD.Options) then + I := FSize + else + I := GetRealSelStart.Index - 1; + if esoSelectedOnly in PSD.Options then + begin + M := PSD.SelStart; + if esoFirstSearch in PSD.Options then + I := PSD.SelEnd + end else + M := 0; + I := Min(I, FSize - N); + if I < M then + PSD.ErrorReason := eseNoMatch + end else + begin + O := 1; + if (esoEntireScope in PSD.Options) and (esoFirstSearch in PSD.Options) then + I := 0 + else + I := GetRealSelEnd.Index; + if esoSelectedOnly in PSD.Options then + begin + M := PSD.SelEnd; + if esoFirstSearch in PSD.Options then + I := PSD.SelStart + end else + M := FSize; + M := Min(M, FSize - N); + if I >= M then + PSD.ErrorReason := eseNoMatch + end; + if PSD.ErrorReason = eseOk then + begin + Found := False; + MatchCase := PSD.Options * [esoMatchCase, esoWereDigits] <> []; + if MatchCase then + C1 := S[1] + else + C1 := UpCase(S[1]); + I := MinMax(I, 0, FSize - 1); + while I <> M do + begin + if MatchCase then + C2 := AnsiChar(FBuffer[I]) + else + C2 := UpCase(AnsiChar(FBuffer[I])); + if C1 = C2 then + begin + if FSize - I >= N then + begin + J := 2; + Dec(I); + while (J <= N) do + begin + if MatchCase then + begin + C2 := AnsiChar(FBuffer[I + J]); + C3 := S[J]; + end else + begin + C2 := Upcase(AnsiChar(FBuffer[I + J])); + C3 := Upcase(S[J]); + end; + if C2 = C3 then + Inc(J) + else + Break; + end; + Inc(I); + if J = N + 1 then + begin + Found := True; + FSelStart := MakeSelection(I, 0); + FSelEnd := MakeSelection(I + N, 0); + if Command = ecReplace then + begin + if (esoPrompt in PSD.Options) and Assigned(FOnReplaceText) then + begin + SelectionChanged(False, False); + if not CaretInView then + ExecuteCommand(ecScrollCenter); + FOnReplaceText(Self, string(S), string(T), ReplaceAction) + end else + ReplaceAction := eraYes; + case ReplaceAction of + eraCancel: Break; + eraYes, eraAll: + begin + if T = '' then + ExecuteCommand(ecClearIndexSelection) + else + ExecuteCommand(ecInsertString, Pointer(T)); + FSelEnd := MakeSelection(I + Length(T), 0); + AddUndoCaretPos; + if ReplaceAction = eraAll then + Include(PSD.Options, esoAll); + end; + end; + if not (esoAll in PSD.Options) then + Break; + end else + Break; + end + end; + end; + Inc(I, O); + end; + if Found then + begin + SelectionChanged(False, False); + if not CaretInView then + ExecuteCommand(ecScrollCenter); + end else + PSD.ErrorReason := eseNoMatch; + end; + end; + Exclude(PSD.Options, esoFirstSearch); + end else + Result := False; + end; + ecInsertMode: + begin + Exclude(FStates, elOverwrite); + UpdateEditorCaret(True); + end; + ecOverwriteMode: + begin + Include(FStates, elOverwrite); + UpdateEditorCaret(True); + end; + ecToggleMode: + begin + if elOverwrite in FStates then + Exclude(FStates, elOverwrite) + else + Include(FStates, elOverwrite); + UpdateEditorCaret(True); + end; + // focus change + ecGotFocus, + ecLostFocus: + begin + UpdateEditorCaret; + Invalidate; + end; + end; + if (OldSelStart.Index <> OldSelEnd.Index) or (FSelStart.Index <> FSelEnd.Index) or + (OldSelStart.Digit <> OldSelEnd.Digit) or (FSelStart.Digit <> FSelEnd.Digit) or + not (elCaretVisible in FStates) and (edInactiveCaret in FDrawStyles) and + ((FSelStart.Index <> OldSelStart.Index) or (FSelStart.Digit <> OldSelStart.Digit) or + (FSelEnd.Index <> OldSelEnd.Index) or (FSelEnd.Digit <> OldSelEnd.Digit)) then + Invalidate; + end; +end; + +procedure TKCustomHexEditor.FontChange(Sender: TObject); +begin + if not (csDestroying in ComponentState) then + begin + Font.Pitch := fpFixed; + if Font.Size >= 0 then + Font.Size := MinMax(Font.Size, cFontSizeMin, cFontSizeMax); + UpdateCharMetrics; + UpdateScrollRange; + end; +end; + +function TKCustomHexEditor.GetAreaDimensions: TKHexEditorAreaDimensions; +begin + FillChar(Result, SizeOf(Result), 0); + with Result do + begin + if edAddress in FDrawStyles then + begin + Address := Length(FAddressPrefix) + FAddressSize; + if FDrawStyles * [edDigits, edText] <> [] then + AddressOut := FAreaSpacing; + end; + if edDigits in FDrawStyles then + begin + Digits := FLineSize * cDigitCount + FLineSize div FDigitGrouping; + if FLineSize mod FDigitGrouping = 0 then + Dec(Digits); + if edAddress in FDrawStyles then + DigitsIn := FAreaSpacing; + if edText in FDrawStyles then + DigitsOut := FAreaSpacing; + end; + if edText in FDrawStyles then + begin + Text := FLineSize; + if FDrawStyles * [edAddress, edDigits] <> [] then + TextIn := FAreaSpacing; + end; + TotalHorz := Address + AddressOut + Digits + DigitsIn + DigitsOut + Text + TextIn; + if [edAddress, edDigits, edText] * FDrawStyles <> [] then + TotalVert := LineCount + else + TotalVert := 0; + end; +end; + +function TKCustomHexEditor.GetCaretVisible: Boolean; +begin + Result := elCaretVisible in FStates; +end; + +function TKCustomHexEditor.GetCharMapping: TKEditCharMapping; +begin + Result := FCharMapping; +end; + +function TKCustomHexEditor.GetClientHeightChars: Integer; +begin + Result := ClientHeight div FCharHeight; +end; + +function TKCustomHexEditor.GetClientWidthChars: Integer; +begin + Result := ClientWidth div FCharWidth; +end; + +function TKCustomHexEditor.GetCommandKey(Index: TKEditCommand): TKEditKey; +var + I: Integer; +begin + Result.Key := 0; + Result.Shift := []; + for I := 0 to Length(FKeyMapping) - 1 do + if FKeyMapping[I].Command = Index then + begin + Result := FKeyMapping[I].Key; + Exit; + end; +end; + +function TKCustomHexEditor.GetData: TDataSize; +begin + Result.Data := FBuffer; + Result.Size := FSize; +end; + +function TKCustomHexEditor.GetEmpty: Boolean; +begin + Result := FBuffer = nil; +end; + +function TKCustomHexEditor.GetFirstVisibleIndex: Integer; +begin + Result := PointToSel(Point(0, 0), False, FEditArea).Index; +end; + +function TKCustomHexEditor.GetInsertMode: Boolean; +begin + Result := not (elOverwrite in FStates); +end; + +function TKCustomHexEditor.GetKeyMapping: TKEditKeyMapping; +begin + Result := FKeyMapping; +end; + +function TKCustomHexEditor.GetLastVisibleIndex: Integer; +begin + Result := PointToSel(GetModifiedClientRect.BottomRight, False, FEditArea).Index; +end; + +function TKCustomHexEditor.GetLineCount: Integer; +begin + Result := DivUp(FSize + 1, FLineSize); +end; + +function TKCustomHexEditor.GetLines(Index: Integer): TDataSize; +var + I: Integer; +begin + I := Index * FLineSize; + if (FBuffer <> nil) and (I >= 0) and (I < FSize) then + begin + Result.Data := @FBuffer[I]; + Result.Size := Min(FLineSize, FSize - I); + end else + begin + Result.Data := nil; + Result.Size := 0; + end; +end; + +function TKCustomHexEditor.GetModified: Boolean; +begin + Result := (elModified in FStates) or FUndoList.Modified; +end; + +function TKCustomHexEditor.GetModifiedClientRect: TRect; +begin + Result := Rect(0, 0, GetClientWidthChars * FCharWidth, GetClientHeightChars * FCharHeight); +end; + +function TKCustomHexEditor.GetMaxLeftChar(Extent: Integer): Integer; +begin + if Extent <= 0 then + Extent := GetAreaDimensions.TotalHorz; + Result := Max(Extent - GetClientWidthChars, 0); +end; + +function TKCustomHexEditor.GetMaxTopLine(Extent: Integer): Integer; +begin + if Extent <= 0 then + Extent := GetAreaDimensions.TotalVert; + Result := Max(Extent - GetClientHeightChars, 0); +end; + +function TKCustomHexEditor.GetPageHorz: Integer; +begin + case FEditArea of + eaDigits: Result := ClientWidth * FDigitgrouping div (FCharWidth * (cDigitCount * FDigitGrouping + 1)); + eaText: Result := ClientWidth div FCharWidth; + else + Result := 0; + end; +end; + +function TKCustomHexEditor.GetReadOnly: Boolean; +begin + Result := elReadOnly in FStates; +end; + +function TKCustomHexEditor.GetRealSelEnd: TKHexEditorSelection; +begin + if FSelStart.Index <= FSelEnd.Index then + Result := FSelEnd + else + Result := FSelStart; +end; + +function TKCustomHexEditor.GetRealSelStart: TKHexEditorSelection; +begin + if FSelStart.Index <= FSelEnd.Index then + Result := FSelStart + else + Result := FSelEnd; +end; + +function TKCustomHexEditor.GetSelLength: TKHexEditorSelection; +begin + if FSelStart.Index <= FSelEnd.Index then + Result.Index := FSelEnd.Index - FSelStart.Index + else + Result.Index := FSelStart.Index - FSelEnd.Index; + if FSelStart.Digit <= FSelEnd.Digit then + Result.Digit := FSelEnd.Digit - FSelStart.Digit + else + Result.Digit := FSelStart.Digit - FSelEnd.Digit; +end; + +function TKCustomHexEditor.GetSelText: TKHexEditorSelText; +var + L, Sel1, Sel2: TKHexEditorSelection; +begin + L := SelLength; + with Result do + begin + if L.Index > 0 then + begin + Sel1 := GetRealSelStart; + Sel2 := GetRealSelEnd; + AsBinaryRaw := BinaryToText(FBuffer, Sel1.Index, Sel2.Index, nil); + AsBinaryMapped := BinaryToText(FBuffer, Sel1.Index, Sel2.Index, @FCharMapping); + AsDigits := BinaryToDigits(FBuffer, Sel1, Sel2); + Sel1.Digit := 0; + Sel2.Digit := 0; + AsDigitsByteAligned := BinaryToDigits(FBuffer, Sel1, Sel2); + end else + begin + AsBinaryRaw := ''; + AsBinaryMapped := ''; + AsDigits := ''; + AsDigitsByteAligned := ''; + end; + end; +end; + +function TKCustomHexEditor.GetUndoLimit: Integer; +begin + Result := FUndoList.Limit; +end; + +function TKCustomHexEditor.HasFocus: Boolean; +var + Form: TCustomForm; +begin + Form := GetParentForm(Self); + if (Form <> nil) and Form.Visible and Form.Enabled and Form.Active then + Result := (Form.ActiveControl = Self) + else + Result := False; +end; + +procedure TKCustomHexEditor.InsertChar(At: Integer; Value: Byte); +begin + InsertString(At, AnsiChar(Value), 1); +end; + +procedure TKCustomHexEditor.InsertString(At: Integer; const Value: AnsiString; Size: Integer); +begin + if (At >= 0) and (At <= FSize) and (Length(Value) > 0) then + begin + Inc(FSize, Size); + ReallocMem(FBuffer, FSize); + if At < FSize - Size then + Move(FBuffer[At], FBuffer[At + Size], (FSize - At - Size) * SizeOf(Byte)); + Move(Value[1], FBuffer[At], Size); + UpdateScrollRange; + end; +end; + +function TKCustomHexEditor.InternalGetSelAvail: Boolean; +begin + Result := SelAvail; +end; + +procedure TKCustomHexEditor.InternalMoveLeft; +begin + if FEditArea = eaDigits then + begin + if FSelEnd.Digit > 0 then + Dec(FSelEnd.Digit) + else if FSelEnd.Index > 0 then + begin + FSelEnd.Digit := cDigitCount - 1; + Dec(FSelEnd.Index); + end + end else + Dec(FSelEnd.Index); +end; + +procedure TKCustomHexEditor.InternalMoveRight; +begin + if FEditArea = eaDigits then + begin + if (FSelEnd.Index < FSize) and (FSelEnd.Digit < cDigitCount - 1) then + Inc(FSelEnd.Digit) + else + begin + FSelEnd.Digit := 0; + Inc(FSelEnd.Index); + end + end else + Inc(FSelEnd.Index); +end; + +function TKCustomHexEditor.IsAddressPrefixStored: Boolean; +begin + Result := FAddressPrefix <> '0x'; +end; + +function TKCustomHexEditor.IsDrawStylesStored: Boolean; +begin + Result := FDrawStyles <> cDrawStylesDef; +end; + +function TKCustomHexEditor.IsOptionsStored: Boolean; +begin + Result := FOptions <> [eoGroupUndo]; +end; + +procedure TKCustomHexEditor.KeyDown(var Key: Word; Shift: TShiftState); +var + I: Integer; + HK: TKEditKey; +begin + inherited; + Exclude(FStates, elIgnoreNextChar); + if not (csDesigning in ComponentState) then + begin + for I := 0 to Length(FKeyMapping) - 1 do + begin + HK := FKeyMapping[I].Key; + if (HK.Key = Key) and (HK.Shift = Shift) then + begin + ExecuteCommand(FKeyMapping[I].Command); + Key := 0; + Include(FStates, elIgnoreNextChar); + Exit; + end; + end; + if Key = VK_ESCAPE then + Include(FStates, elIgnoreNextChar); + end; +end; + +procedure TKCustomHexEditor.KeyPress(var Key: Char); +var + I: Integer; +begin + inherited; + if not (csDesigning in ComponentState) then + begin + if not (elIgnoreNextChar in FStates) then + begin + case FEditArea of + eaDigits: I := DigitToBin(AnsiChar(Key)); + eaText: I := Ord(Key); + else + I := -1; + end; + if I >= 0 then + ExecuteCommand(ecInsertChar, @I); + end else + Exclude(FStates, elIgnoreNextChar); + end; +end; + +procedure TKCustomHexEditor.LoadFromFile(const FileName: TFileName); +var + Stream: TFileStream; +begin + Stream := TFileStream.Create(FileName, fmOpenRead); + try + LoadFromStream(Stream); + finally + Stream.Free; + end; +end; + +procedure TKCustomHexEditor.LoadFromStream(Stream: TStream); +var + Size: Integer; +begin + Size := Stream.Size - Stream.Position; + if Size > 0 then + begin + Clear; + FSize := Size; + GetMem(FBuffer, FSize); + Stream.Read(FBuffer^, FSize); + BufferChanged; + end; +end; + +procedure TKCustomHexEditor.MeasurePages(var Info: TKPrintMeasureInfo); +var + AD: TKHexEditorAreaDimensions; + PageLines, ActiveLines: Integer; + FitToPage, SelOnly: Boolean; + Scale: Double; + APageSetup: TKPrintPageSetup; +begin + APageSetup := PageSetup; + FitToPage := poFitToPage in APageSetup.Options; + SelOnly := APageSetup.Range = prSelectedOnly; + Scale := APageSetup.Scale / 100; + AD := GetAreaDimensions; + Info.OutlineWidth := AD.TotalHorz * FCharWidth; + if FitToPage then + Scale := APageSetup.PaintAreaWidth / Info.OutlineWidth; + PageLines := Round(APageSetup.PaintAreaHeight / Scale) div FCharHeight; + if SelOnly then + ActiveLines := DivUp(GetRealSelEnd.Index, FLineSize) - GetRealSelStart.Index div FLineSize + else + ActiveLines := LineCount; + Info.OutlineHeight := PageLines * FCharHeight; + Info.HorzPageCount := 1; // cut text off + Info.VertPageCount := DivUp(ActiveLines, PageLines); + Info.PageCount := Info.VertPageCount; +end; + +procedure TKCustomHexEditor.ModifyScrollBar(ScrollBar, ScrollCode, + Delta: Integer; UpdateNeeded: Boolean); +var + I, J, K: Integer; + HasScrollBar: Boolean; + SI: TScrollInfo; +begin + HasScrollBar := (ScrollBar = SB_HORZ) and (ScrollBars = ssHorizontal) or + (ScrollBar = SB_VERT) and (ScrollBars = ssVertical) or (ScrollBars = ssBoth); + if HasScrollBar then + begin + FillChar(SI, SizeOf(TScrollInfo), 0); + SI.cbSize := SizeOf(TScrollInfo); + SI.fMask := SIF_PAGE or SIF_TRACKPOS; + GetScrollInfo(Handle, ScrollBar, SI); + {$IF DEFINED(LCLGTK2)} + {.$WARNING "scrollbar arrows still not working properly on GTK2 in some cases!"} + SI.nTrackPos := Delta; + {$IFEND} + end; + if ScrollBar = SB_HORZ then + begin + I := FLeftChar; + J := GetMaxLeftChar; + end else + begin + I := FTopLine; + J := GetMaxTopLine; + end; + K := I; + if ScrollCode = cScrollDelta then + Inc(I, Delta) + else if HasScrollBar then + case ScrollCode of + SB_LINEUP: Dec(I); + SB_LINEDOWN: Inc(I); + SB_PAGEUP: Dec(I, SI.nPage); + SB_PAGEDOWN: Inc(I, SI.nPage); + SB_THUMBTRACK, SB_THUMBPOSITION: I := SI.nTrackPos; + end; + I := MinMax(I, 0, J); + if K <> I then + begin + if HasScrollBar then + begin + FillChar(SI, SizeOf(TScrollInfo), 0); + SI.nPos := I; + SI.fMask := SIF_POS; + SetScrollInfo(Handle, ScrollBar, SI, True); + end; + if ScrollBar = SB_HORZ then + FLeftChar := I + else + FTopLine := I; + if UpdateNeeded then + begin + UpdateEditorCaret; + Invalidate; + end; + end; +end; + +procedure TKCustomHexEditor.MouseDown(Button: TMouseButton; Shift: TShiftState; + X, Y: Integer); +var + P: TPoint; + Command: TKEditCommand; +begin + inherited; + if Enabled and (Button = mbLeft) and not (ssDouble in Shift) then + begin + SafeSetFocus; + P := Point(X, Y); + if ssShift in Shift then + Command := ecSelGotoXY + else + Command := ecGotoXY; + if ExecuteCommand(Command, @P) then + Include(FStates, elMouseCapture); + end; +end; + +procedure TKCustomHexEditor.MouseMove(Shift: TShiftState; X, Y: Integer); +var + P: TPoint; + R: TRect; +begin + inherited; + if (elMouseCapture in FStates) then + begin + P := Point(X, Y); + R := GetModifiedClientRect; + if PtInRect(R, P) then + UpdateSelEnd(P, False) + else if not FScrollTimer.Enabled then + ScrollTo(P, True, False); + end; +end; + +procedure TKCustomHexEditor.MouseUp(Button: TMouseButton; Shift: TShiftState; + X, Y: Integer); +begin + inherited; + Exclude(FStates, elMouseCapture); +end; + +procedure TKCustomHexEditor.PaintLines(const Data: TKHexEditorPaintData); +var + HalfPosWidth, I, Index, J, K, L, M, MaxAddress, WHorz, WVert, WSep, + LeftIndent, VTextIndent: Integer; + BC1, BC2, FC1, FC2, PC1: TColor; + EditorFocused, DrawInactiveCaret, DrawNormal, DigitSep, SelCondition: Boolean; + S: AnsiString; + Fmt: string; + C: Char; + R, R1, RClip: TRect; + OldColorScheme: TKHexEditorColorScheme; + ASelStart, ASelEnd: TKHexEditorSelection; + AD: TKHexEditorAreaDimensions; +begin + { this function must be reentrant because of print function + so there is necessary to backup all changes to global properties} + OldColorScheme := FColors.ColorScheme; + with Data.Canvas do + try + R := Data.PaintRect; + AD := GetAreaDimensions; + // add possible inter-character spacing (in Lazarus not fully implemented yet) + SetTextCharacterExtra(Handle, Data.CharSpacing); + LeftIndent := R.Left - Data.LeftChar * Data.CharWidth; + VTextIndent := (Data.CharHeight - Abs(Font.Height)) div 2; + HalfPosWidth := Data.CharWidth div 2; + Fmt := ''; + MaxAddress := 0; + L := LineCount; + DrawInactiveCaret := not (Data.Printing or Data.CaretShown) and + (edInactiveCaret in FDrawStyles); + DrawNormal := not Data.Printing; + EditorFocused := HasFocus; + if FSelStart.Index <= FSelEnd.Index then + begin + ASelStart := FSelStart; + ASelEnd := FSelEnd; + end else + begin + ASelStart := FSelEnd; + ASelEnd := FSelStart; + end; + // preserve space for lines and separators + if edHorzLines in FDrawStyles then + WVert := Max(1, Data.CharHeight div 25) + else + WVert := 0; + if edVertLines in FDrawStyles then + WHorz := Max(1, Data.CharWidth div 20) + else + WHorz := 0; + if edSeparators in FDrawStyles then + WSep := Max(1, Data.CharWidth div 20) + else + WSep := 0; + // address area pre-comp + if edAddress in FDrawStyles then + begin + if FAddressMode = eamDec then + begin + C := 'd'; + J := 10; + end else + begin + C := 'x'; + J := 16; + end; + Fmt := Format('%s%%.%d%s', [FAddressPrefix, FAddressSize, C]); + MaxAddress := 1; + for I := 1 to FAddressSize do + MaxAddress := MaxAddress * J; + end; + // update color scheme + if Data.Printing then + begin + if Data.PaintColors then + FColors.ColorScheme := ecsNormal + else + FColors.ColorScheme := ecsGrayScale; + end else + begin + if Enabled or (FDisabledDrawStyle = eddNormal) then + FColors.ColorScheme := ecsNormal + else if FDisabledDrawStyle = eddGrayed then + FColors.ColorScheme := ecsGrayed + else + FColors.ColorScheme := ecsBright + end; + FColors.SingleBkGnd := edSingleBkGnd in FDrawStyles; + // get clip box for updating; + if Data.Printing then + RClip := R + else + GetClipBox(Handle, {$IFDEF FPC}@{$ENDIF}RClip); + // now paint text lines + for I := Data.TopLine to Min(L - 1, Data.BottomLine) do + begin + Brush.Style := bsSolid; + K := LeftIndent; + R.Bottom := R.Top + Data.CharHeight - WVert; + if (R.Top <= RClip.Bottom) and (R.Bottom >= RClip.Top) then + begin + if edAddress in FDrawStyles then + begin + Index := I * FLineSize; + Brush.Color := clRed; + if (DrawNormal or Data.PaintSelection) and ((ASelStart.Index <> ASelEnd.Index) or (ASelStart.Digit <> ASelEnd.Digit)) and + (Index + FLineSize - 1 >= ASelStart.Index) and (Index < ASelEnd.Index) then + begin + PC1 := FColors.LinesHighLight; + if (FEditArea = eaAddress) and (EditorFocused or Data.PaintSelection) then + begin + FC1 := FColors.SelTextFocused; + BC1 := FColors.SelBkGndFocused; + end else + begin + FC1 := FColors.SelText; + BC1 := FColors.SelBkGnd; + end; + end else + begin + PC1 := FColors.HorzLines; + FC1 := FColors.AddressText; + BC1 := FColors.AddressBkGnd; + end; + Brush.Color := BC1; + Font.Color := FC1; + R.Left := K; + Inc(K, AD.Address * Data.CharWidth); + R.Right := K; + J := I * FLineSize + FAddressOffset; + if MaxAddress <> 0 then J := J mod MaxAddress; + FillRect(R); + TextOut(R.Left, R.Top + VTextIndent, Format(Fmt, [J])); + if edHorzLines in FDrawStyles then + begin + Brush.Color := PC1; + FillRect(Rect(R.Left, R.Bottom, R.Right, R.Bottom + WVert)); + end; + if AD.AddressOut > 0 then + begin + R.Left := K; + Inc(K, AD.AddressOut * Data.CharWidth); + R.Right := K; + Brush.Color := FColors.AddressBkGnd; + FillRect(Rect(R.Left, R.Top, R.Right - WSep, R.Bottom)); + if edHorzLines in FDrawStyles then + begin + Brush.Color := FColors.HorzLines; + FillRect(Rect(R.Left, R.Bottom, R.Right - WSep, R.Bottom + WVert)); + end; + end; + end; + if edDigits in FDrawStyles then + begin + if AD.DigitsIn > 0 then + begin + R.Left := K; + Inc(K, AD.DigitsIn * Data.CharWidth); + R.Right := K; + Brush.Color := FColors.DigitBkGnd; + FillRect(Rect(R.Left + WSep, R.Top, R.Right, R.Bottom)); + if edHorzLines in FDrawStyles then + begin + Brush.Color := FColors.HorzLines; + FillRect(Rect(R.Left + WSep, R.Bottom, R.Right, R.Bottom + WVert)); + end; + end; + Index := 0; + for J := 0 to FLineSize - 1 do + begin + Index := I * FLineSize + J; + DigitSep := (J < FLineSize - 1) and ((J + 1) mod FDigitGrouping = 0); + R.Left := K; + Inc(K, cDigitCount * Data.CharWidth); + R.Right := K; + if Index <= FSize then + begin + if Index < FSize then + S := AnsiString(Format(cFmtText, [FBuffer[Index]])) + else + S := ' '; + if (Index <> FSelStart.Index) and (Index <> FSelEnd.Index) then + begin + SelCondition := (Index >= ASelStart.Index) and (Index < ASelEnd.Index); + if (DrawNormal or Data.PaintSelection) and SelCondition then + begin + PC1 := FColors.LinesHighLight; + if (FEditArea = eaDigits) and (EditorFocused or Data.PaintSelection) then + begin + FC1 := FColors.SelTextFocused; + BC1 := FColors.SelBkGndFocused; + end else + begin + FC1 := FColors.SelText; + BC1 := FColors.SelBkGnd; + end; + FC2 := FColors.InactiveCaretSelText; + BC2 := FColors.InactiveCaretSelBkGnd; + end else + begin + PC1 := FColors.HorzLines; + if DrawNormal or Data.PaintAll or SelCondition then + begin + if (J div FDigitGrouping) and 1 = 0 then + FC1 := FColors.DigitTextEven + else + FC1 := FColors.DigitTextOdd; + end else + FC1 := FColors.DigitBkGnd; + BC1 := FColors.DigitBkGnd; + FC2 := FColors.InactiveCaretText; + BC2 := FColors.InactiveCaretBkGnd; + end; + Brush.Color := BC1; + Font.Color := FC1; + Brush.Style := bsSolid; + FillRect(R); + Brush.Style := bsClear; + TextOut(R.Left, R.Top + VTextIndent, Char(S[1])); + TextOut(R.Left + Data.CharWidth, R.Top + VTextIndent, Char(S[2])); + if (Index = FSelEnd.Index) and DrawInactiveCaret then + begin + // draw inactive caret - place into previous drawn text + R1 := R; + Inc(R1.Left, Data.CharWidth * Min(FSelEnd.Digit, cDigitCount - 1)); + R1.Right := R1.Left + Data.CharWidth; + Font.Color := FC2; + Brush.Color := BC2; + Brush.Style := bsSolid; + FillRect(R1); + Brush.Style := bsClear; + TextOut(R1.Left, R1.Top + VTextIndent, string(S)); + end; + if edHorzLines in FDrawStyles then + begin + Brush.Color := PC1; + Brush.Style := bsSolid; + FillRect(Rect(R.Left, R.Bottom, R.Right, R.Bottom + WVert)); + end; + end else + begin + R1 := R; + R1.Right := R1.Left; + Inc(R1.Right, Data.CharWidth); + for M := 0 to cDigitCount - 1 do + begin + SelCondition := + (ASelStart.Index = ASelEnd.Index) and ( + (M >= ASelStart.Digit) and (M < ASelEnd.Digit) or + (M >= ASelEnd.Digit) and (M < ASelStart.Digit) + ) + or + (ASelStart.Index <> ASelEnd.Index) and ( + (Index = ASelStart.Index) and (M >= ASelStart.Digit) or + (Index = ASelEnd.Index) and (M < ASelEnd.Digit) + ); + if (DrawNormal or Data.PaintSelection) and SelCondition then + begin + PC1 := FColors.LinesHighLight; + if DrawInactiveCaret and (Index = FSelEnd.Index) and (M = FSelEnd.Digit) then + begin + FC1 := FColors.InactiveCaretSelText; + BC1 := FColors.InactiveCaretSelBkGnd; + end + else if (FEditArea = eaDigits) and (EditorFocused or Data.PaintSelection) then + begin + FC1 := FColors.SelTextFocused; + BC1 := FColors.SelBkGndFocused; + end else + begin + FC1 := FColors.SelText; + BC1 := FColors.SelBkGnd; + end; + end else + begin + PC1 := FColors.HorzLines; + if DrawInactiveCaret and (Index = FSelEnd.Index) and (M = FSelEnd.Digit) then + begin + FC1 := FColors.InactiveCaretText; + BC1 := FColors.InactiveCaretBkGnd; + end else + begin + if DrawNormal or Data.PaintAll or SelCondition then + begin + if (J div FDigitGrouping) and 1 = 0 then + FC1 := FColors.DigitTextEven + else + FC1 := FColors.DigitTextOdd; + end else + FC1 := FColors.DigitBkGnd; + BC1 := FColors.DigitBkGnd; + end; + end; + Brush.Color := BC1; + Font.Color := FC1; + Brush.Style := bsSolid; + FillRect(R1); + Brush.Style := bsClear; + TextOut(R1.Left, R1.Top + VTextIndent, Char(S[M + 1])); + if edHorzLines in FDrawStyles then + begin + Brush.Color := PC1; + Brush.Style := bsSolid; + FillRect(Rect(R1.Left, R1.Bottom, R1.Right, R1.Bottom + WVert)); + end; + R1.Left := R1.Right; + Inc(R1.Right, Data.CharWidth); + end; + end; + if DigitSep then + begin + if Index < FSize then + M := Data.CharWidth + else + M := HalfPosWidth; + Brush.Color := FColors.DigitBkGnd; + Brush.Style := bsSolid; + FillRect(Rect(R.Right, R.Top, R.Right + Data.CharWidth, R.Bottom)); + if edHorzLines in FDrawStyles then + begin + Brush.Color := FColors.HorzLines; + FillRect(Rect(R.Right, R.Bottom, R.Right + M, R.Bottom + WVert)); + end; + if edVertLines in FDrawStyles then + begin + M := R.Right + HalfPosWidth; + Brush.Color := FColors.VertLines; + FillRect(Rect(M, R.Top, M + WHorz, R.Bottom)); + end; + Inc(K, Data.CharWidth); + end; + end else + begin + Inc(K, Integer(DigitSep) * Data.CharWidth); + Brush.Color := FColors.DigitBkGnd; + Brush.Style := bsSolid; + FillRect(Rect(R.Left, R.Top, K, R.Bottom + WVert)); + end; + end; + if AD.DigitsOut > 0 then + begin + R.Left := K; + Inc(K, AD.DigitsOut * Data.CharWidth); + R.Right := K; + Brush.Style := bsSolid; + Brush.Color := FColors.DigitBkGnd; + FillRect(Rect(R.Left, R.Top, R.Right - WSep, R.Bottom)); + if edHorzLines in FDrawStyles then + begin + if Index < FSize then + Brush.Color := FColors.HorzLines + else + Brush.Color := FColors.DigitBkGnd; + FillRect(Rect(R.Left, R.Bottom, R.Right - WSep, R.Bottom + WVert)); + end; + end; + end; + if edText in FDrawStyles then + begin + if AD.TextIn > 0 then + begin + R.Left := K; + Inc(K, AD.TextIn * Data.CharWidth); + R.Right := K; + Brush.Color := FColors.TextBkGnd; + Brush.Style := bsSolid; + FillRect(Rect(R.Left + WSep, R.Top, R.Right, R.Bottom)); + if edHorzLines in FDrawStyles then + begin + Brush.Color := FColors.HorzLines; + FillRect(Rect(R.Left + WSep, R.Bottom, R.Right, R.Bottom + WVert)); + end; + end; + for J := 0 to FLineSize - 1 do + begin + Index := I * FLineSize + J; + R.Left := K; + Inc(K, Data.CharWidth); + R.Right := K; + if Index <= FSize then + begin + SelCondition := (Index >= ASelStart.Index) and (Index < ASelEnd.Index); + if (DrawNormal or Data.PaintSelection) and SelCondition then + begin + PC1 := FColors.LinesHighLight; + if DrawInactiveCaret and (Index = FSelEnd.Index) then + begin + FC1 := FColors.InactiveCaretSelText; + BC1 := FColors.InactiveCaretSelBkGnd; + end + else if (FEditArea = eaText) and (EditorFocused or Data.PaintSelection) then + begin + FC1 := FColors.SelTextFocused; + BC1 := FColors.SelBkGndFocused; + end else + begin + FC1 := FColors.SelText; + BC1 := FColors.SelBkGnd; + end; + end else + begin + PC1 := FColors.HorzLines; + if DrawInactiveCaret and (Index = FSelEnd.Index) then + begin + FC1 := FColors.InactiveCaretText; + BC1 := FColors.InactiveCaretBkGnd; + end else + begin + if DrawNormal or Data.PaintAll or SelCondition then + FC1 := FColors.TextText + else + FC1 := FColors.TextBkgnd; + BC1 := FColors.TextBkgnd; + end; + end; + Brush.Color := BC1; + Brush.Style := bsSolid; + FillRect(R); + Brush.Style := bsClear; + if Index < FSize then + begin + Font.Color := FC1; + TextOut(R.Left, R.Top + VTextIndent, Char(FCharMapping[FBuffer[Index]])); + end; + if edHorzLines in FDrawStyles then + begin + Brush.Color := PC1; + Brush.Style := bsSolid; + FillRect(Rect(R.Left, R.Bottom, R.Right, R.Bottom + WVert)); + end; + end else + begin + Brush.Color := FColors.TextBkGnd; + Brush.Style := bsSolid; + FillRect(Rect(R.Left, R.Top, K, R.Bottom + WVert)); + end; + end; + end; + end; + Inc(R.Top, Data.CharHeight); + end; + // now complete blank areas below text and optionally paint separators + K := LeftIndent; + R.Bottom := Data.PaintRect.Bottom; + Brush.Style := bsSolid; + if edAddress in FDrawStyles then + begin + R.Left := K; + Inc(K, (AD.Address + AD.AddressOut) * Data.CharWidth); + R.Right := K; if FDrawStyles * [edDigits, edText] <> [] then Dec(R.Right, WSep); + if R.Top < R.Bottom then + begin + Brush.Color := FColors.AddressBkGnd; + FillRect(R); + end; + if (edSeparators in FDrawStyles) and (FDrawStyles * [edDigits, edText] <> []) then + begin + Brush.Color := FColors.Separators; + FillRect(Rect(K - WSep, Data.PaintRect.Top, K + WSep, Data.PaintRect.Bottom)); + end; + end; + if edDigits in FDrawStyles then + begin + R.Left := K; if edAddress in FDrawStyles then Inc(R.Left, WSep); + Inc(K, (AD.Digits + AD.DigitsIn + AD.DigitsOut) * Data.CharWidth); + R.Right := K; if edText in FDrawStyles then Dec(R.Right, WSep); + if R.Top < R.Bottom then + begin + Brush.Color := FColors.DigitBkGnd; + FillRect(R); + end; + if (edSeparators in FDrawStyles) and (edText in FDrawStyles) then + begin + Brush.Color := FColors.Separators; + FillRect(Rect(K - WSep, Data.PaintRect.Top, K + WSep, Data.PaintRect.Bottom)); + end; + end; + if edText in FDrawStyles then + begin + R.Left := K; if FDrawStyles * [edAddress, edDigits] <> [] then Inc(R.Left, WSep); + Inc(K, (AD.TextIn + AD.Text) * Data.CharWidth); + R.Right := K; + if R.Top < R.Bottom then + begin + Brush.Color := FColors.TextBkGnd; + FillRect(R); + end; + end; + if K < ClientWidth then + begin + Brush.Color := FColors.BkGnd; + FillRect(Rect(K, 0, ClientWidth, ClientHeight)); + end; + finally + FColors.ColorScheme := OldColorScheme; + end; +end; + +procedure TKCustomHexEditor.PaintPage; +var + ActiveLines, AreaWidth, AreaHeight, FirstLine, PageLines: Integer; + SelOnly: Boolean; + TmpRect, TmpRect1: TRect; + APageSetup: TKPrintPageSetup; + Data: TKHexEditorPaintData; +begin + APageSetup := PageSetup; + SelOnly := APageSetup.Range = prSelectedOnly; + AreaWidth := Round(APageSetup.PaintAreaWidth / APageSetup.CurrentScale); + AreaHeight := Round(APageSetup.PaintAreaHeight / APageSetup.CurrentScale); + PageLines := AreaHeight div FCharHeight; + if SelOnly then + begin + FirstLine := GetRealSelStart.Index div FLineSize; + ActiveLines := DivUp(GetRealSelEnd.Index, FLineSize) - FirstLine; + end else + begin + FirstLine := 0; + ActiveLines := LineCount; + end; + TmpRect := Rect(0, 0, APageSetup.OutlineWidth, APageSetup.OutlineHeight); + TmpRect1 := Rect(0, 0, AreaWidth, AreaHeight); + IntersectRect(TmpRect, TmpRect, TmpRect1); + TmpRect1 := TmpRect; + TranslateRectToDevice(APageSetup.Canvas.Handle, TmpRect1); + SelectClipRect(APageSetup.Canvas.Handle, TmpRect1); + Data.Canvas := APageSetup.Canvas; + Data.Canvas.Font := Font; + Data.Canvas.Font.Height := Abs(Font.Height); + Data.PaintRect := TmpRect; + Data.TopLine := (APageSetup.CurrentPage - 1) * PageLines; + Data.BottomLine := Min(Data.TopLine + PageLines, ActiveLines) - 1; + Inc(Data.TopLine, FirstLine); + Inc(Data.BottomLine, FirstLine); + Data.LeftChar := 0; + Data.CharWidth := FCharWidth; + Data.CharHeight := FCharHeight; + Data.CharSpacing := FTotalCharSpacing; + Data.Printing := True; + Data.PaintSelection := poPaintSelection in APageSetup.Options; + Data.PaintAll := not SelOnly; + Data.PaintColors := poUseColor in APageSetup.Options; + PaintLines(Data); +end; + +procedure TKCustomHexEditor.PaintToCanvas(ACanvas: TCanvas); +var + Data: TKHexEditorPaintData; +begin + ACanvas.Font := Font; + with Data do + begin + Canvas := ACanvas; + PaintRect := ClientRect; + LeftChar := FLeftChar; + TopLine := FTopLine; + CharWidth := FCharWidth; + CharHeight := FCharHeight; + BottomLine := TopLine + ClientHeight div FCharHeight; + CharSpacing := FTotalCharSpacing; + Printing := False; + PaintSelection := False; + CaretShown := elCaretVisible in FStates; + end; +{$IFDEF FPC} + if Data.CaretShown then + HideEditorCaret; + try +{$ENDIF} + PaintLines(Data); +{$IFDEF FPC} + finally + if Data.CaretShown then + ShowEditorCaret; + end; +{$ENDIF} +end; + +procedure TKCustomHexEditor.PaintToCanvasEx(ACanvas: TCanvas; ARect: TRect; ALeftChar, ATopLine: Integer); +var + Data: TKHexEditorPaintData; + Region: HRGN; +begin + ACanvas.Font := Font; + with Data do + begin + Canvas := ACanvas; + PaintRect := ARect; + LeftChar := ALeftChar; + TopLine := ATopLine; + CharWidth := FCharWidth; + CharHeight := FCharHeight; + BottomLine := TopLine + (ARect.Bottom - ARect.Top) div FCharHeight; + CharSpacing := FTotalCharSpacing; + Printing := False; + PaintSelection := False; + end; + Region := CreateRectRgnIndirect(ARect); + try + SelectClipRgn(ACanvas.Handle, Region); + try + PaintLines(Data); + finally + SelectClipRgn(ACanvas.Handle, 0); + end; + finally + DeleteObject(Region); + end; +end; + +function TKCustomHexEditor.PointToSel(P: TPoint; OutOfArea: Boolean; var Area: TKHexEditorArea): TKHexEditorSelection; +var + Digit, HalfPosWidth, I, X, X1, XMax: Integer; + DigitSep: Boolean; + AD: TKHexEditorAreaDimensions; + Sel: TKHexEditorSelection; +begin + Result := MakeSelection(cInvalidIndex, 0); + P.X := P.X + FLeftChar * FCharWidth; + P.Y := P.Y div FCharHeight + FTopLine; + AD := GetAreaDimensions; + HalfPosWidth := FCharWidth div 2; + X := 0; + if OutOfArea then + P.Y := MinMax(P.Y, 0, LineCount - 1) + else + Area := eaNone; + if P.Y < LineCount then + begin + if edAddress in FDrawStyles then + begin + XMax := X + (AD.Address + AD.AddressOut) * FCharWidth; + if not OutOfArea or (Area = eaAddress) then + if (P.X >= X) and (P.X < XMax) then + begin + Result := MakeSelection(P.Y * FLineSize, 0); + Area := eaAddress; + end + else if Area = eaAddress then // OutOfArea = True + begin + Result.Index := P.Y * FLineSize; + if P.X >= XMax then + Inc(Result.Index, FLineSize); + end; + X := XMax; + end; + if (P.X >= X) or OutOfArea then + begin + if edDigits in FDrawStyles then + begin + XMax := X + (AD.Digits + AD.DigitsIn + AD.DigitsOut) * FCharWidth; + if not OutOfArea or (Area = eaDigits) then + if (P.X >= X) and (P.X < XMax) then + begin + Inc(X, AD.DigitsIn * FCharWidth); + for I := 0 to FLineSize - 1 do + begin + DigitSep := (I < FLineSize - 1) and ((I + 1) mod FDigitGrouping = 0); + X1 := X; + Inc(X, cDigitCount * FCharWidth); + if DigitSep then + Inc(X, HalfPosWidth) + else if I = FLineSize - 1 then + Inc(X, AD.DigitsOut * FCharWidth); + if P.X < X then + begin + Digit := (Max(P.X - X1, 0) + HalfPosWidth) div FCharWidth; + Sel := MakeSelection(P.Y * FLineSize + I, Digit); + if (Digit >= cDigitCount) and (Sel.Index < FSize) then // don't split the FSize character box + begin + Inc(Sel.Index); + Sel.Digit := 0; + end; + if (Sel.Index <= FSize) or OutOfArea then + begin + Result := Sel; + Area := eaDigits; + end; + Break; + end; + if DigitSep then + Inc(X, HalfPosWidth); + end; + end + else if Area = eaDigits then // OutOfArea = True + begin + Result.Index := P.Y * FLineSize; + if P.X >= XMax then + Inc(Result.Index, FLineSize); + end; + X := XMax; + end; + if ((P.X >= X) or OutOfArea) and (edText in FDrawStyles) then + begin + XMax := X + (AD.Text + AD.TextIn) * FCharWidth; + if not OutOfArea or (Area = eaText) then + if (P.X >= X) and (P.X < XMax) then + begin + Inc(X, AD.TextIn * FCharWidth); + Sel := MakeSelection(P.Y * FLineSize, 0); + I := Max(P.X - X, 0) div FCharWidth; + if Sel.Index + I = FSize then + Sel.Index := FSize // don't split the FSize character box + else + Inc(Sel.Index, (Max(P.X - X, 0) + HalfPosWidth) div FCharWidth); + if (Sel.Index <= FSize) or OutOfArea then + begin + Result := Sel; + Area := eaText; + end; + end + else if Area = eaText then // OutOfArea = True + begin + Result.Index := P.Y * FLineSize; + if P.X >= XMax then + Inc(Result.Index, FLineSize); + end; + end; + end; + end; + ValidateSelection(Result, Area); +end; + +procedure TKCustomHexEditor.SafeSetFocus; +var + Form: TCustomForm; +begin + Form := GetParentForm(Self); + if (Form <> nil) and Form.Visible and Form.Enabled and not (csDestroying in Form.ComponentState) + and Visible and Enabled then + Form.ActiveControl := Self; +end; + +procedure TKCustomHexEditor.SaveToFile(const FileName: TFileName); +var + Stream: TFileStream; +begin + Stream := TFileStream.Create(FileName, fmCreate); + try + SaveToStream(Stream); + finally + Stream.Free; + end; +end; + +procedure TKCustomHexEditor.SaveToStream(Stream: TStream); +begin + if FBuffer <> nil then + Stream.Write(FBuffer^, FSize); +end; + +procedure TKCustomHexEditor.ScrollBy(HChars, VChars: Integer; UpdateNeeded: Boolean); +begin + if HChars <> 0 then + ModifyScrollBar(SB_HORZ, cScrollDelta, HChars, UpdateNeeded); + if VChars <> 0 then + ModifyScrollBar(SB_VERT, cScrollDelta, VChars, UpdateNeeded); +end; + +procedure TKCustomHexEditor.ScrollTo(Point: TPoint; Timed, AlwaysScroll: Boolean); +var + ScrollHorz: Boolean; + R: TRect; +begin + // disable horizontal overscroll when scrolling e.g. with mouse + ScrollHorz := AlwaysScroll or (FSelEnd.Index mod FLineSize <> 0) and + (FSelEnd.Index < FSize) or (FSelEnd.Digit > 0); + R := GetModifiedClientRect; + if ScrollHorz then + begin + if Point.X < R.Left then + FScrollDeltaX := DivDown(Point.X, FCharWidth) + else if Point.X >= R.Right then + FScrollDeltaX := (Point.X - R.Right) div FCharWidth + 1 + else + FScrollDeltaX := 0; + end else + FScrollDeltaX := 0; + if Point.Y < R.Top then + FScrollDeltaY := DivDown(Point.Y, FCharHeight) + else if Point.Y >= R.Bottom then + FScrollDeltaY := (Point.Y - R.Bottom) div FCharHeight + 1 + else + FScrollDeltaY := 0; + if (FScrollDeltaX <> 0) or (FScrollDeltaY <> 0) then + if Timed then + begin + ScrollBy(FScrollDeltaX, FScrollDeltaY, False); + FScrollTimer.Enabled := True; + end else + ScrollBy(FScrollDeltaX, FScrollDeltaY, True); + UpdateSelEnd(Point, True); +end; + +procedure TKCustomHexEditor.ScrollTimerHandler(Sender: TObject); +var + P: TPoint; +begin + GetCursorPos(P); + P := ScreenToClient(P); + if (elMouseCapture in FStates) and not (Dragging or + PtInRect(GetModifiedClientRect, P)) then + ScrollTo(P, True, False) + else + FScrollTimer.Enabled := False; +end; + +function TKCustomHexEditor.SelAvail: Boolean; +begin + Result := SelLength.Index > 0; +end; + +procedure TKCustomHexEditor.SelectionChanged(StartEqualEnd: Boolean; ScrollToView: Boolean = True); +begin + ValidateSelection(FSelEnd, FEditArea); + if StartEqualEnd then + FSelStart := FSelEnd + else + ValidateSelection(FSelStart, FEditArea); + if HasParent then + begin + if ScrollToView and (FEditArea <> eaNone) then + ScrollTo(SelToPoint(FSelEnd, FEditArea), False, True); + UpdateEditorCaret; + Invalidate; + InvalidatePageSetup; + end; +end; + +function TKCustomHexEditor.SelectionValid(Value: TKHexEditorSelection; Area: TKHexEditorArea): Boolean; +begin + Result := (Area <> eaNone) and ( + (Value.Index >= 0) and (Value.Index < FSize) or + (Value.Index = FSize) and (Value.Digit = 0)) +end; + +function TKCustomHexEditor.SelToPoint(Value: TKHexEditorSelection; Area: TKHexEditorArea): TPoint; +var + AD: TKHexEditorAreaDimensions; +begin + Result := Point(0, 0); + AD := GetAreaDimensions; + ValidateSelection(Value, Area); + if (Area = eaDigits) and (edDigits in FDrawStyles) then + begin + Result.X := ((Value.Index mod FLineSize) div FDigitGrouping * (cDigitCount * FDigitGrouping + 1) + + (Value.Index mod FLineSize) mod FDigitGrouping * cDigitCount + Value.Digit + AD.DigitsIn) + end else if (Area = eaText) and (edText in FDrawStyles) then + Result.X := (Value.Index mod FLineSize + AD.DigitsIn + AD.Digits + AD.DigitsOut + AD.TextIn) + else if Area = eaAddress then + begin + if edDigits in FDrawStyles then + Result.X := AD.DigitsIn + else if edText in FDrawStyles then + Result.X := AD.TextIn; + end; + Result.X := (Result.X + AD.Address + AD.AddressOut - FLeftChar) * FCharWidth; + Result.Y := (Value.Index div FLineSize - FTopLine) * FCharHeight; +end; + +procedure TKCustomHexEditor.SetAddressCursor(Value: TCursor); +begin + if Value <> FAddressCursor then + begin + FAddressCursor := Value; + UpdateMouseCursor; + end; +end; + +procedure TKCustomHexEditor.SetAddressMode(Value: TKHexEditorAddressMode); +begin + if Value <> FAddressMode then + begin + FAddressMode := Value; + Invalidate; + end; +end; + +procedure TKCustomHexEditor.SetAddressOffset(Value: Integer); +begin + if Value <> FAddressOffset then + begin + FAddressOffset := Value; + Invalidate; + end; +end; + +procedure TKCustomHexEditor.SetAddressPrefix(const Value: string); +begin + if Value <> FAddressPrefix then + begin + FAddressPrefix := Value; + UpdateScrollRange; + end; +end; + +procedure TKCustomHexEditor.SetAddressSize(Value: Integer); +begin + Value := MinMax(Value, cAddressSizeMin, cAddressSizeMax); + if Value <> FAddressSize then + begin + FAddressSize := Value; + UpdateScrollRange; + end; +end; + +procedure TKCustomHexEditor.SetAreaSpacing(Value: Integer); +begin + Value := MinMax(Value, cAreaSpacingMin, cAreaSpacingMax); + if Value <> FAreaSpacing then + begin + FAreaSpacing := Value; + UpdateScrollRange; + end; +end; + +procedure TKCustomHexEditor.SetCharMapping(const Value: TKEditCharMapping); +begin + if not CompareMem(@Value, @FCharMapping, SizeOf(TKEditCharMapping)) and + (edText in FDrawStyles) then + Invalidate; +end; + +procedure TKCustomHexEditor.SetCharSpacing(Value: Integer); +begin + Value := MinMax(Value, cCharSpacingMin, cCharSpacingMax); + if Value <> FCharSpacing then + begin + FCharSpacing := Value; + UpdateCharMetrics; + UpdateScrollRange; + end; +end; + +procedure TKCustomHexEditor.SetColors(Value: TKHexEditorColors); +begin + FColors.Assign(Value); +end; + +procedure TKCustomHexEditor.SetCommandKey(Index: TKEditCommand; Value: TKEditKey); +var + I: Integer; +begin + for I := 0 to Length(FKeyMapping) - 1 do + if FKeyMapping[I].Command = Index then + begin + FKeyMapping[I].Key := Value; + Exit; + end; +end; + +procedure TKCustomHexEditor.SetData(Value: TDataSize); +begin + if (Value.Data <> FBuffer) or (Value.Size <> FSize) then + begin + Clear; + if Value.Data <> nil then + begin + FSize := Value.Size; + GetMem(FBuffer, FSize); + System.Move(Value.Data^, FBuffer^, FSize); + BufferChanged; + end; + end; +end; + +procedure TKCustomHexEditor.SetDigitGrouping(Value: Integer); +begin + Value := MinMax(Value, cDigitGroupingMin, Min(FLineSize, cDigitGroupingMax)); + if Value <> FDigitGrouping then + begin + FDigitGrouping := Value; + UpdateScrollRange; + end; +end; + +procedure TKCustomHexEditor.SetDisabledDrawStyle(Value: TKHexEditorDisabledDrawStyle); +begin + if Value <> FDisabledDrawStyle then + begin + FDisabledDrawStyle := Value; + if not Enabled then + Invalidate; + end; +end; + +procedure TKCustomHexEditor.SetDrawStyles(const Value: TKHexEditorDrawStyles); +begin + if Value <> FDrawStyles then + begin + FDrawStyles := Value; + EditAreaChanged; // must be called first + UpdateScrollRange; + end; +end; + +procedure TKCustomHexEditor.SetEditArea(Value: TKHexEditorArea); +begin + if Value <> FEditArea then + begin + FEditArea := Value; + EditAreaChanged; + if Value <> FEditArea then + Invalidate; + end; +end; + +procedure TKCustomHexEditor.SetKeyMapping(const Value: TKEditKeyMapping); +begin + SetLength(FKeyMapping, Length(Value)); + Move(Value, FKeyMapping, Length(Value) * SizeOf(TKEditCommandAssignment)); +end; + +procedure TKCustomHexEditor.SetLineHeightPercent(Value: Integer); +begin + Value := MinMax(Value, cLineHeightPercentMin, cLineHeightPercentMax); + if Value <> FLineHeightPercent then + begin + FLineHeightPercent := Value; + UpdateCharMetrics; + UpdateScrollRange; + end; +end; + +procedure TKCustomHexEditor.SetLeftChar(Value: Integer); +begin + Value := MinMax(Value, 0, GetMaxLeftChar); + if Value <> FLeftChar then + ScrollBy(Value - FLeftChar, 0, True); +end; + +procedure TKCustomHexEditor.SetLines(Index: Integer; const Value: TDataSize); +var + I, Size: Integer; +begin + I := Index * FLineSize; + if (Value.Data <> nil) and (Value.Size > 0) and (I >= 0) and (I <= FSize) then + begin + Size := Min(FLineSize, Value.Size); + if I + Size > FSize then + begin + FSize := Size; + ReallocMem(FBuffer, FSize); + end; + System.Move(Value.Data^, FBuffer[I], Size); + BufferChanged; + end; +end; + +procedure TKCustomHexEditor.SetLineSize(Value: Integer); +begin + Value := MinMax(Value, cLineSizeMin, cLineSizeMax); + if Value <> FLineSize then + begin + FLineSize := Value; + UpdateScrollRange; + end; +end; + +procedure TKCustomHexEditor.SetModified(Value: Boolean); +begin + if Value <> GetModified then + begin + if Value then + Include(FStates, elModified) + else + begin + Exclude(FStates, elModified); + if eoUndoAfterSave in FOptions then + FUndoList.Modified := False + else + begin + FUndoList.Clear; + FRedoList.Clear; + end; + end; + end; +end; + +function TKCustomHexEditor.SetMouseCursor(X, Y: Integer): Boolean; +var + ACursor: TCursor; + P: TPoint; + Area: TKHexEditorArea; +begin + P := Point(X, Y); + PointToSel(P, False, Area); + if PtInRect(ClientRect, P) then + begin + case Area of + eaAddress: ACursor := FAddressCursor; + eaDigits: ACursor := crIBeam; + eaText: ACursor := crIBeam; + else + ACursor := crDefault; + end; + end else + ACursor := crDefault; +{$IFDEF FPC} + FCursor := ACursor; + SetTempCursor(ACursor); +{$ELSE} + Windows.SetCursor(Screen.Cursors[ACursor]); +{$ENDIF} + Result := True; +end; + +procedure TKCustomHexEditor.SetOptions(const Value: TKEditOptions); +{$IFDEF USE_WINAPI} +var + UpdateDropFiles: Boolean; +{$ENDIF} +begin + if Value <> FOptions then + begin + {$IFDEF USE_WINAPI} + UpdateDropFiles := (eoDropFiles in Value) <> (eoDropFiles in FOptions); + FOptions := Value; + // (un)register HWND as drop target + if UpdateDropFiles and not (csDesigning in ComponentState) and HandleAllocated then + DragAcceptFiles(Handle, (eoDropFiles in fOptions)); + {$ELSE} + FOptions := Value; + {$ENDIF} + end; +end; + +procedure TKCustomHexEditor.SetReadOnly(Value: Boolean); +begin + if Value <> GetReadOnly then + begin + if Value then + Include(FStates, elReadOnly) + else + Exclude(FStates, elReadOnly); + end; +end; + +procedure TKCustomHexEditor.SetScrollBars(Value: TScrollStyle); +begin + if Value <> FScrollBars then + begin + FScrollBars := Value; + {$IFDEF FPC} + UpdateSize; + {$ELSE} + RecreateWnd; + {$ENDIF} + end; +end; + +procedure TKCustomHexEditor.SetScrollSpeed(Value: Cardinal); +begin + Value := MinMax(Integer(Value), cScrollSpeedMin, cScrollSpeedMax); + if Value <> FScrollSpeed then + begin + FScrollSpeed := Value; + FScrollTimer.Enabled := False; + FScrollTimer.Interval := FScrollSpeed; + end; +end; + +procedure TKCustomHexEditor.SetSelEnd(Value: TKHexEditorSelection); +begin + if (Value.Index <> FSelEnd.Index) or (Value.Digit <> FSelEnd.Digit) then + begin + FSelEnd := Value; + SelectionChanged(False, False); + Invalidate; + end; +end; + +procedure TKCustomHexEditor.SetSelLength(Value: TKHexEditorSelection); +var + X: TKHexEditorSelection; +begin + X := GetSelLength; + if (Value.Index <> X.Index) or (Value.Digit <> X.Digit) then + begin + FSelEnd.Index := FSelStart.Index + Value.Index; + FSelEnd.Digit := FSelStart.Digit + Value.Digit; + if FSelEnd.Digit >= cDigitCount then + Inc(FSelEnd.Index); + SelectionChanged(False, False); + Invalidate; + end; +end; + +procedure TKCustomHexEditor.SetSelStart(Value: TKHexEditorSelection); +begin + if (Value.Index <> FSelStart.Index) or (Value.Digit <> FSelStart.Digit) then + begin + FSelStart := Value; + SelectionChanged(False, False); + Invalidate; + end; +end; + +procedure TKCustomHexEditor.SetTopLine(Value: Integer); +begin + Value := MinMax(Value, 0, GetMaxTopLine); + if Value <> FTopLine then + ScrollBy(0, Value - FTopLine, True); +end; + +procedure TKCustomHexEditor.SetUndoLimit(Value: Integer); +begin + Value := MinMax(Value, cUndoLimitMin, cUndoLimitMax); + if Value <> FUndoList.Limit then + begin + FUndoList.Limit := Value; + FRedoList.Limit := Value; + end; +end; + +procedure TKCustomHexEditor.HideEditorCaret; +var + P: TPoint; +begin + P := SelToPoint(FSelEnd, FEditArea); + HideCaret(Handle); + {$IFDEF FPC}SetCaretPosEx(Handle,{$ELSE}SetCaretPos({$ENDIF} P.X, P.Y + 1); +end; + +procedure TKCustomHexEditor.ShowEditorCaret; +var + P: TPoint; +begin + P := SelToPoint(FSelEnd, FEditArea); + {$IFDEF FPC}SetCaretPosEx(Handle,{$ELSE}SetCaretPos({$ENDIF} P.X, P.Y + 1); + ShowCaret(Handle); +end; + +procedure TKCustomHexEditor.UndoChange(Sender: TObject; ItemReason: TKHexEditorChangeReason); +begin + if (Sender = FUndoList) and (ItemReason <> crCaretPos) then + DoChange; +end; + +procedure TKCustomHexEditor.UpdateEditorCaret(Recreate: Boolean = False); +var + CW, CH: Integer; +begin + Include(FStates, elCaretUpdate); + try + if Enabled and Focused and (FEditArea in [eaDigits, eaText]) and not (csDesigning in ComponentState) then + begin + if not (elCaretVisible in FStates) or Recreate then + begin + if elOverwrite in FStates then + CW := FCharWidth + else + CW := Max(2, (Abs(Font.Height) * 2) div 25); + if edHorzLines in FDrawStyles then + CH := FCharHeight - Max(1, FCharHeight div 25) + else + CH := FCharHeight; + {$IFDEF FPC} + CreateCaret(Handle, 0, CW, CH - 2); + {$ELSE} + if CreateCaret(Handle, 0, CW, CH - 2) then + {$ENDIF} + Include(FStates, elCaretVisible); + Invalidate; + end; + if elCaretVisible in FStates then + ShowEditorCaret; + end else + begin + Exclude(FStates, elCaretVisible); + HideEditorCaret; + {$IFDEF FPC} + DestroyCaret(Handle); + {$ELSE} + DestroyCaret; + {$ENDIF} + end; + finally + Exclude(FStates, elCaretUpdate); + end; +end; + +procedure TKCustomHexEditor.UpdateCharMetrics; +var + DC: HDC; + TM: TTextMetric; +begin + DC := GetDC(0); + try + SelectObject(DC, Font.Handle); + GetTextMetrics(DC, TM); + FTotalCharSpacing := FCharSpacing * 2; + // ensure even char spacing because of PointToSel + if TM.tmAveCharWidth and 1 <> 0 then + Inc(FTotalCharSpacing); + FCharWidth := TM.tmAveCharWidth + FTotalCharSpacing; + FCharHeight := TM.tmHeight * FLineHeightPercent div 100; + finally + ReleaseDC(0, DC); + end; +end; + +procedure TKCustomHexEditor.UpdateMouseCursor; +var + P: TPoint; +begin + P := ScreenToClient(Mouse.CursorPos); + SetMouseCursor(P.X, P.Y); +end; + +procedure TKCustomHexEditor.UpdateScrollRange; +var + I: Integer; + AD: TKHexEditorAreaDimensions; + SI: TScrollInfo; +begin + if HandleAllocated then + begin + AD := GetAreaDimensions; + // update horizontal scroll position + I := FLeftChar - GetMaxLeftChar(AD.TotalHorz); + if I > 0 then + Dec(FLeftChar, I); + FLeftChar := Max(FLeftChar, 0); + // update vertical scroll position + I := FTopLine - GetMaxTopLine(AD.TotalVert); + if I > 0 then + Dec(FTopLine, I); + FTopLine := Max(FTopLine, 0); + if FScrollBars in [ssBoth, ssHorizontal, ssVertical] then + begin + SI.cbSize := SizeOf(TScrollInfo); + SI.fMask := SIF_RANGE or SIF_PAGE or SIF_POS {$IFDEF UNIX}or SIF_UPDATEPOLICY{$ENDIF}; + SI.nMin := 0; + {$IFDEF UNIX} + SI.ntrackPos := SB_POLICY_CONTINUOUS; + {$ENDIF} + if FScrollBars in [ssBoth, ssHorizontal] then + begin + SI.nMax := AD.TotalHorz{$IFNDEF FPC}- 1{$ENDIF}; + SI.nPage := GetClientWidthChars; + SI.nPos := FLeftChar; + SetScrollInfo(Handle, SB_HORZ, SI, True); + ShowScrollBar(Handle, SB_HORZ, Integer(SI.nPage) < AD.TotalHorz); + end else + ShowScrollBar(Handle, SB_HORZ, False); + if FScrollBars in [ssBoth, ssVertical] then + begin + SI.nMax := AD.TotalVert{$IFNDEF FPC}- 1{$ENDIF}; + SI.nPage := GetClientHeightChars; + SI.nPos := FTopLine; + SetScrollInfo(Handle, SB_VERT, SI, True); + ShowScrollBar(Handle, SB_VERT, Integer(SI.nPage) < AD.TotalVert); + end else + ShowScrollBar(Handle, SB_VERT, False); + end; + UpdateEditorCaret(True); + Invalidate; + InvalidatePageSetup; + end; +end; + +procedure TKCustomHexEditor.UpdateSelEnd(Point: TPoint; ClipToClient: Boolean); +var + R: TRect; + Sel: TKHexEditorSelection; +begin + if ClipToClient then + begin + R := GetModifiedClientRect; + Dec(R.Right, FCharWidth); + Dec(R.Bottom, FCharHeight); + if CanScroll(ecScrollLeft) and (Point.X < R.Left) then + Point.X := R.Left + else if CanScroll(ecScrollRight) and (Point.X > R.Right) then + Point.X := R.Right; + if CanScroll(ecScrollUp) and (Point.Y < R.Top) then + Point.Y := R.Top + else if CanScroll(ecScrollDown) and (Point.Y > R.Bottom) then + Point.Y := R.Bottom; + end; + Sel := PointToSel(Point, True, FEditArea); + if (Sel.Index <> cInvalidIndex) and + ((Sel.Index <> FSelEnd.Index) or (Sel.Digit <> FSelEnd.Digit)) then + begin + FSelEnd := Sel; + UpdateEditorCaret; + Invalidate; + InvalidatePageSetup; + end; +end; + +procedure TKCustomHexEditor.UpdateSize; +begin + UpdateScrollRange; +end; + +procedure TKCustomHexEditor.ValidateSelection(var Value: TKHexEditorSelection; Area: TKHexEditorArea); +begin + if Area <> eaNone then + begin + Value.Index := MinMax(Value.Index, 0, FSize); + if Value.Index = FSize then + Value.Digit := 0 + else + Value.Digit := MinMax(Value.Digit, 0, cDigitCount - 1); + end else + Value := MakeSelection(cInvalidIndex, 0); +end; + +{$IFNDEF FPC} +procedure TKCustomHexEditor.WMDropFiles(var Msg: TLMessage); +var + I, FileCount: Integer; + PathName: array[0..260] of Char; + Point: TPoint; + FilesList: TStringList; +begin + try + if Assigned(FOnDropFiles) then + begin + FilesList := TStringList.Create; + try + FileCount := DragQueryFile(THandle(Msg.wParam), Cardinal(-1), nil, 0); + DragQueryPoint(THandle(Msg.wParam), Point); + for i := 0 to FileCount - 1 do + begin + DragQueryFile(THandle(Msg.wParam), I, PathName, SizeOf(PathName)); + FilesList.Add(PathName); + end; + FOnDropFiles(Self, Point.X, Point.Y, FilesList); + finally + FilesList.Free; + end; + end; + finally + Msg.Result := 0; + DragFinish(THandle(Msg.wParam)); + end; +end; +{$ENDIF} + +procedure TKCustomHexEditor.WMEraseBkgnd(var Msg: TLMessage); +begin + Msg.Result := 1; +end; + +procedure TKCustomHexEditor.WMGetDlgCode(var Msg: TLMNoParams); +begin + Msg.Result := DLGC_WANTARROWS; +end; + +procedure TKCustomHexEditor.WMHScroll(var Msg: TLMHScroll); +begin + SafeSetFocus; + ModifyScrollBar(SB_HORZ, Msg.ScrollCode, Msg.Pos, True); +end; + +procedure TKCustomHexEditor.WMKillFocus(var Msg: TLMKillFocus); +begin + inherited; + ExecuteCommand(ecLostFocus); +end; + +procedure TKCustomHexEditor.WMSetFocus(var Msg: TLMSetFocus); +begin + inherited; + ExecuteCommand(ecGotFocus); +end; + +procedure TKCustomHexEditor.WMVScroll(var Msg: TLMVScroll); +begin + SafeSetFocus; + ModifyScrollBar(SB_VERT, Msg.ScrollCode, Msg.Pos, True); +end; + +function GetColorSpec(Index: TKHexEditorColorIndex): TKHexEditorColorSpec; +begin + case Index of + ciAddressText: begin Result.Def := cAddressTextDef; Result.Name := sAddressText; end; + ciAddressBkGnd: begin Result.Def := cAddressBkgndDef; Result.Name := sAddressBkGnd; end; + ciBkGnd: begin Result.Def := cBkGndDef; Result.Name := sBkGnd; end; + ciDigitTextEven: begin Result.Def := cDigitTextEvenDef; Result.Name := sDigitTextEven; end; + ciDigitTextOdd: begin Result.Def := cDigitTextOddDef; Result.Name := sDigitTextOdd; end; + ciDigitBkGnd: begin Result.Def := cDigitBkGndDef; Result.Name := sDigitBkgnd; end; + ciHorzLines: begin Result.Def := cHorzLinesDef; Result.Name := sHorzLines; end; + ciInactiveCaretBkGnd: begin Result.Def := cInactiveCaretBkGndDef; Result.Name := sInactiveCaretBkGnd; end; + ciInactiveCaretSelBkGnd: begin Result.Def := cInactiveCaretSelBkGndDef; Result.Name := sInactiveCaretSelBkGnd; end; + ciInactiveCaretSelText: begin Result.Def := cInactiveCaretSelTextDef; Result.Name := sInactiveCaretSelText; end; + ciInactiveCaretText: begin Result.Def := cInactiveCaretTextDef; Result.Name := sInactiveCaretText; end; + ciLinesHighLight: begin Result.Def := cLinesHighLightDef; Result.Name := sLinesHighLight; end; + ciSelBkGnd: begin Result.Def := cSelBkGndDef; Result.Name := sSelBkGnd; end; + ciSelBkGndFocused: begin Result.Def := cSelBkGndFocusedDef; Result.Name := sSelBkGndFocused; end; + ciSelText: begin Result.Def := cSelTextDef; Result.Name := sSelText; end; + ciSelTextFocused: begin Result.Def := cSelTextFocusedDef; Result.Name := sSelTextFocused; end; + ciSeparators: begin Result.Def := cSeparatorsDef; Result.Name := sSeparators; end; + ciTextText: begin Result.Def := cTextTextDef; Result.Name := sTextText; end; + ciTextBkGnd: begin Result.Def := cTextBkgndDef; Result.Name := sTextBkGnd; end; + ciVertLines: begin Result.Def := cVertLinesDef; Result.Name := sVertLines; end; + else + Result.Def := clNone; + Result.Name := ''; + end; +end; + +end. diff --git a/components/kcontrols/source/khexeditordesign.lrs b/components/kcontrols/source/khexeditordesign.lrs new file mode 100755 index 000000000..69123036f --- /dev/null +++ b/components/kcontrols/source/khexeditordesign.lrs @@ -0,0 +1,262 @@ +LazarusResources.Add('tkhexeditor','PNG',[ + #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#24#0#0#0#24#8#6#0#0#0#224'w='#248#0 + +#0#0#4'gAMA'#0#0#177#142'|'#251'Q'#147#0#0#0' cHRM'#0#0'z%'#0#0#128#131#0#0 + +#249#255#0#0#128#232#0#0'u0'#0#0#234'`'#0#0':'#151#0#0#23'o'#151#169#153#212 + +#0#0#4#12'IDATx'#156'b'#252#255#255'?'#3'y`?'#19#144'`'#7'b^ '#22#1'bq('#27#4 + +'>'#1#241#11' ~'#3#16'@,$'#24#200#12'$X'#160#24#198#6#25'('#5#196'*@'#172#250 + +#231#213#127#241#239#167#254#243#253'y'#199#254#155'M'#254#207'6n'#251#255 + +#199#1#2#8'n'#1'###V'#175#0#197#25'XY'#153#25'xx8'#25'xy'#185#24#184#184'8' + +#24#216#217'Y'#193'b""'#252#12#26#26'r'#12'&Z'#26#12#218'3'#213#25#184'~'#9 + +'2'#176#201's3|'#150#253#196#160#19#199#185#14#168#157#21' '#128'P|@lp'#253 + +#251#252#155#129#129#137#145#129#137#27#162'}'#157#199't'#134#215'7?2'#200 + +#240'q1'#252#229'gc'#224#239'V'#6#138'>'#3'*b'#248#5#16'@'#24'A'#196#200#216 + +#136'da='#3'7w+'#131#148#20''''#131#158#158#16#131#137#137'0'#131#217#3'f'#6 + +#149#223#252#12'o'#253#217#24#140#252'M'#25'NN^'#205#240#247#232'G'#6'i'#14 + +#21#6'fA6'#6#233#185#22#12'O'#153#159#128#180#191#3#226'o'#0#1#132'a'#1#200 + +'Pd'#240#245'k5'#156#189#196#178#151#129#235#154' '#3's'#160' '#131#142#182#6 + +#195#183'G'#31#25#174'u\c0`'#6#26'.'#204#198' V'#175#199#192#174#202#203#240 + +#227#218'O'#144#242#151' '#11#0#2#136#160#15'$%'#187#192'.'#15#10#146'g8p~' + +#31#131'>G'#12'D'#238#215'3'#134#147'yg'#24#20'>'#139'1p'#139#243'0'#240#7 + +#139'2\'#149'z'#193'`'#197' '#199#240#253#251'/'#144#146'7@'#252#3' '#128#8 + +#250#224#249#243'28{wF'#15'0'#249'03'#252'}'#251#147#225#221#220'/'#12#12'G>' + +'1'#136'3'#9'3p;J0'#136#214#152'0'#136's2'#131#213#253#253#251#15'D'#1#227 + +#192#241#31'@'#0#17#244#129#130'B/'#131#189#189'8C|'#188'2\'#252#231#141#143 + +#12#223'N'#191'e'#16'd'#226'c`'#228'`'#6')d'#248'u'#251#30#195#133'o'#31#24 + +',,L'#25#152#153'AY'#4#148'G'#246#255#2#8' '#130'>x'#240#160#24#206#158#3#165 + +#255'~'#254#195#240#227#199#15#134'{'#127#159'2'#8'}'#227'e`'#187#194#195#240 + +'~.'#11#131'A'#162#10'X'#158#147#19#148#255#190#138#2#137'?'#0#1'D'#148#15#28 + +#28'@>P'#129#139#179#136#176'3'#200'&I1'#188#186#201#196#176'o'#241#30#6#167 + +#171#12#192#144#7#2'fF'#6'!'#14'U`~'#225#4#241#20#129#248';@'#0#145#228#131 + +#217'P'#154'M'#129#135#129'UN'#154#193#189#200#146#225#206#191''''#12#251#150 + +#158#1'["'#207#206#196#240'q'#229#3#6#142'0'#30#144'2P'#14#127#2#16'@'#4'} #' + +#211#205'`n.'#10'LEr('#234#152#249#191#130#233#192'Fo'#134#13#12'_'#24#142'/' + +#189#204#192'z'#158#133'A'#242#215'?'#6'n&'#9#134'?'#25'L'#162','#162#255'8' + +#1#2#136#17#150'{AE'#5#161#156#28#195#238#201#16#196#230#200#160#202','#203 + +' ;'#209#156'A ^'#9','#254#253#195'W'#134'Ei'#211#24'x>'#177#2'c'#150#141'A' + +#239#159#2#131#176#15#235#20#225'<'#150#185#0#1#132'j'#1#194#233'`'#159#128 + +'| '#208#206' '#15',_tt'#4#25'T>>`'#14#150#230'b'#224#231'ge'#168#174#246'c'#184'u'#235#10 + +#131#154#218'kG'#160'I'#15#1#2#8#167#5#148#128's'#231'N3'#24#25'}'#1#165#235 + +#15#0#1#132#221#2'd'#128','#170'('#9'LB'#192't'#15#202'H'#223#129#197#193#243 + +#183#16'qn'#14#136#248'G`'#188#8#243#1'KC'#160#158#247#155'@1'#253#27' '#128 + +#240#251#0'XT'#195#249#172','#224#18#148#225#231'o'#136#24#136#15#178#232#223 + +'?Tu'#8'6'#152#1#16'@LD'#251#251#207'_`'#225#251#7'b'#0#8#131#248'0'#135#160 + +'9'#232#224#129#3'pm'#0#1'DB'#141#134#230';"'#1'@'#0#17#31'D'#200'l|rhA'#4#16 + +'@X'#131#232#224#193#131'`'#140#194#135'y'#27#22'D'#12#144#160'@W'#135#14#0#2 + +#136#145#252'V'#5'q'#0' '#128#136#143'd2'#1'@'#128#1#0#188' dE'#131#162#228 + +'T'#0#0#0#0'IEND'#174'B`'#130 +]); +LazarusResources.Add('tkprintpreview','PNG',[ + #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#24#0#0#0#24#8#6#0#0#0#224'w='#248#0 + +#0#0#4'gAMA'#0#0#177#142'|'#251'Q'#147#0#0#0' cHRM'#0#0'z%'#0#0#128#131#0#0 + +#249#255#0#0#128#232#0#0'u0'#0#0#234'`'#0#0':'#151#0#0#23'o'#151#169#153#212 + +#0#0#6#175'IDATx'#156'b'#252#255#255'?'#3'###'#3#26'P'#7'bk fF'#151#128#1'VV' + +'fF'#1#1'^'#150#162#162#208#253#21#21#145' '#3#196#129#152#23'*'#253#9#136'_' + +#0#241#27#128#0'b'#193#162'7'#207#221#221#189'/<<'#156#153#149#149#21','#0'r' + +#196#127' '#253#239#223'?'#134'_'#191#127'3|'#250#242#157#225#213#219#247#12 + +#127'~'#255'`8v'#236#240#221#7#15'^'#244')(HH'#252'y'#245'_'#252#251#169#255 + +'|'#127#222#177#255'f'#147#255#179#141#219#254#255'q'#128#0'bD'#243#129#140 + +#189#189#253#189#237';v'#178#190#255#240#137#225'/'#208'@'#16#128'H3'#2'-' + +#249#199#240#251#207'_'#134#239#223#127'2'#188#253#240#129#129#149#133#153'A' + +'B'#144#157#225#234#233'M'#31#149'{'#228#217'Y~'#242'p'#176#201's3'#176#169 + +#179#191#150#236#254#145#6#212't'#5' '#128#208'}`'#228#229#229#205#250#225 + +#211'g'#134#159'@'#151#194#12#7'9'#128#133#153#9#136'Y'#24#216#128#134'r'#252 + +'a`'#224#17#20'f`'#228'fb'#16#23#17'a8'#155#193#193#255#244#198#27#6#25'>V' + +#134#191#188#140#127'EK'#255#173#1#234#2#25#240#11' '#128#152#208',`ffa'#6 + +#187#150#133#153#25#138#129#134#178#178'0'#176#179#177'2pq'#178'1'#252'['#254 + +#130#225'_'#251'c'#6#161#223#28#12'b'#194#252#12#23'f'#29'f'#248#127#236#27 + +#131'4'#187'8'#3#179' '#27#131#232'$'#150#27',b'#140#15#129#134#188#3#226'o' + +#0#1#132#25#7#192' cf'#2#6#7#208#240#210#226'B'#6#7#7'{'#6'IIQ'#6'aa.'#134#27 + +'9'''#24'4nK3'#200#6'j'#2'-'#252#193#240#231'%'#3#195#181#246#227#12#6#204'*' + +#12#204#194'l'#12'"5*'#12#187#238#175#149#214#230#146'y'#163#161'!'#247#18'd' + +#1'@'#0#161#251#0'd>'#3#19#19#19#208#18'&'#134#212#212'4'#6'C#c'#6'Y9y'#6#25 + +#25'y'#134#3'WN0'#240'0rB'#212#253'bc8'#153#177#147'A'#225#179#24#3#183'('#15 + +#3#127#176','#3'O'#176'"P}'#176'@v'#246#212#170#204#204'~P'#204#253#0#8' ,' + +#22#252#135'X'#0#12's'#14'NN'#134#175#223#190'1'#176#178's2|'#249#247#159#225 + +#247#255#191#192't'#203#204#240#247#237'O'#134'ws'#31'00'#28#249#202' '#206 + +'$'#204#192#237'('#206' Z'#163#202#240#233#243#7#134#151#239#191'3(i'#152')m' + +#218't'#220#132#129#193#241#31'@'#0'aZ'#192#0#178#128#17'l'#201#219#247#31#25 + +#254#176'p0'#156'|'#244#140'AZT'#26#174#230#231#141#143#12#31#150'>c'#16'd' + +#226'c`'#228'`'#6'ib'#248'u'#251#3'0'#142#184#24#132#5#249#25#196'D'#133#24 + +#132#132'x'#129'i|?3@'#0'a'#245#1'('#213#252#250#253#135#129#137#149#131'a' + +#251#149#187#12':**'#12#191#160'I'#22#4#254'~'#254#195#240#227#199#15#134#187 + +#127#159'2'#188#248#246#138#225#199#149#143#12#239#231#2#243#213#245#239#192 + +'T%'#196#160#166','#195#160#163#163#200#7'T'#202#9#16'@'#24#145#12#14'"F&' + +#134'g/_3'#220'|'#249#129#129'_L'#148#225#237#175#223#12#146#127'~'#194#213 + +#176#136#176'3'#200'&'#169'2'#188#186#249#151'a'#223#226#131#12'NW'#25#24#228 + +#192'i'#144#145'A E'#129'AIQ'#138#193#216'X'#21#148#179#5#0#2#8'k$3'#2#131 + +#232#237#187#143#12'w'#223'|`'#248#250#235#23#195#251#31#191#24#190#253#250#1 + +'W'#195#166#192#195#192'*'#199#206#224'>'#211#135'A"Z'#129'a'#223#159'3'#12 + +#143#174#222'c'#248'~'#238#29#195#231#213'O'#25'$'#152#133#129#137'BL'#8#168 + +#148#15' '#128#176#250#0#20#253#159#191'~'#5#27#254#229#203#15#134'w_'#190'1' + +#188#255#134#170#148#153#159#149#225#253#247#223#12'Q'#147#210#24#150'3'#204 + +'d8'#190#244'2'#3#235'y'#22#6#201'_'#255#24#184#25'D'#24#4#180#249#193'A'#4 + +#16'@'#216#131#8#24#193#255#254#254'c'#224#5'f'#176#23#159'>'#0#195'['#140 + +#225#211#15'`'#156#0#173#190#241#247#1#131#234#145#191#12#255'|'#4#24#158'*' + +#253'f'#248#241#247'/'#131'Vn'#0#195#197#215#235#24#238'}}'#207#240#130#249 + +#23#131#198#254#175#12#28'_'#185'D'#24'B'#24#254#2#4#16'N'#31#240#243#241'0' + +#200#11#240'0<'#127#249#150#225'70'#14'>|'#254#198#224#148#23#204' '#160'%' + +#199#240#133#135#135#225#157#18#11#195#179'w_'#24#222'}'#252#194#240#253#219 + +'W'#6#139':'#31#6'9q'#17#6')qi'#134#157#187#214'3'#156'?w'#230#132#3#131#198 + +'G'#128#0#194#154#138'@'#5#144#154#146'<'#195#231#215#175#24'd9'#217#25'>' + +#127#252#204#240#237#251#31#6#209'pC'#6'&3i'#134#239#154#252#12#175#127'~'#5 + +#166#251#31#12'O'#158#191'c'#248#255#237#31#195#181#171#183#24#4#248'E'#24 + +#128#217#133#225'9P'#236#194#133#219#175#129#198'}'#4#8' ,>``x'#252#236'%' + +#195#174'C'''#25#148#149#20#24#190#253#248#201#240#20'T'#6'n.N'#244#16'F'#196'#'#20#0#4#16#204#130#249'v'#158#193#186 + +#22#150'V'#12#252#188'<'#12#183#238'=f8}'#233':'#131#139#189'%'#131#149#177 + +#30'$'#236#128#254#255#11'L'#146#204#204'8'#171'i0'#0#213#130#127#254#128'+' + +#171#191' '#2' '#128#160#22'0r'#139'KJ'#131'S'#207#165'k'#183#24#238'>|'#194 + +#224'lk'#198'`'#172#171#201#240#243#215'o'#20#3'@U&.'#0#170#179#223#188#251 + +#192#176'w'#207#30#144#166's 1'#128#0#130'Z'#240#191'y'#255#182'5'#214','#192 + +'Hx'#3'L'#154'O'#239'^e'#16#229#250#199'p'#253#226'Y'#188#174'E'#7#191#129'.' + +#223#182'e'#243#223'S''O'#148#0#185'O@b'#0#1#132'\'#233#187#2#233#6' '#253#11 + +'('#6#162#149#25#240'4[p'#0#144#247#142#2#241'M'#176#179#129'f'#3#4#24#0#252 + +'1e'#249#212#25#172'k'#0#0#0#0'IEND'#174'B`'#130 +]); +LazarusResources.Add('tkprintpreviewdialog','PNG',[ + #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#24#0#0#0#24#8#6#0#0#0#224'w='#248#0 + +#0#0#4'gAMA'#0#0#177#142'|'#251'Q'#147#0#0#0' cHRM'#0#0'z%'#0#0#128#131#0#0 + +#249#255#0#0#128#232#0#0'u0'#0#0#234'`'#0#0':'#151#0#0#23'o'#151#169#153#212 + +#0#0#5#198'IDATx'#156'b'#252#255#255'?'#3'y`?'#19#144'`'#7'b^ '#22#1'bq('#27 + +#4'>'#1#241#11' ~'#3#16'@,'#251#246#29#248#191'k'#215'e'#130#198'111'#194'1#' + +'##'#3'33'#19#3';;'#11#3'//'#7#131#136#8#15#131#176'07'#3#215#127#22#6#166 + +''''#255#24'Dx'#4#25'$D?Fr'#219#255'?'#14#16'@, '#195#195#211#146#240#26#14 + +'4'#143#129#9'd('#19#136'f'#0'['#0#18'S'#191'u'#144#225#169#158'#'#131#216 + +#179'+'#12'w3_00'#127#254#201#192'&'#207#205#240'W'#253';'#3'w'#247#255#31'@' + +#173#172#0#1#196#2'2'#224#228#205'/'#184']'#206#8'R'#197#200#192#205#193#196 + +#192#3#196#28'l'#140#12#236'?'#255'2X'#254#186#206'p'#244#212'U'#6'ku9'#134 + +#213#133#187#25#4'/'#241'2'#200#240'I2'#252#229'cax'#225#246#159#225#243'E' + +#254#245#250#250#31#229#1#2#8'l'#193#229#7'_qZ'#192#6'4'#156#159#155#153'AZ' + +#152#133#129#159#139#149'Ax'#227'S'#6#193'G?'#24#30#165#170'2XgJ3'#156'\t'#11 + +#232'B'#6#6'i'#14'q'#6'fA6'#6#134'.]'#134#143#31'.3'#176#255#249#11#210#254 + +#13' '#128#192#22#240'>'#220#138#211#2'..6'#6#17'q'#1#6'9q'#9#134'giG'#24#248 + +'nK2'#8#7'j2H'#8'}c'#248#246#225'7'#195#181#246#19#12#6#204#170#12#204#194'l' + +#12#130'U'#210#12#247'Y'#238'3'#188'}'#251#133'A@'#0#28#223#223#0#2#8'lAGG.' + +#134#193#215#175'_gX'#180'h'#17'0'#172#217#25'8'#217#254'0'#8#243#243'2,'#187 + +'r'#140#193#132'#'#6','#255#255#23#23#195#201#188#189#12#10#159#197#25#184 + +#197'y'#24#248#131#229#25'D"'#245#193#201#233#248#241'E'#12'rr`'#31#252#0#8 + +' '#22#152#129#15#30#220#129#27#254#237#219'7'#134#137#19#167'2'#180'ut'#2'S' + +#13#19#3#11#11'3'#3#27'+3'#195#239#255#147#24#152#129#240#239#219#159#12#239 + +#230#2#131#230#200''''#6'q&a'#6'nGq'#6#209#26'e'#160#190#247'@s'#30'3'#252 + +#252#249#135#225#223'?P'#242'w'#252#7#16'@,'#12'X'#192#157';w'#24'\'#221#220 + +#25'>'#127#253#206#192#2'L:'#28#236#172#192#136'f'#135#203#255#188#241#145 + +#225#219#233'?'#12#130'L|'#12#140#28#204'@'#239'00'#252#186#253#141#129'Y' + +#157#157#129#21#232#16'P'#242#5'%g`^a'#6#8' &l'#22#128#242#30'()'#178#178#176 + +'0'#236#219#187#131#225#241#227#187#12#159'>>'#131#203#255#253#252#135#225 + +#199#143#31#12'w'#255'>ex'#241#237#21#195#143'+'#31#25#222#207'}'#196#240#239 + +#218'w'#6#30#30'Np'#190'`c'#3#187#157#19' '#128#176#250#0'j'#13#208#2'f'#6'Y' + +'Yy'#6#14#14'.`ze'#133#203#176#136#176'3'#200'&'#169'1'#188#186#249#159'a' + +#223#226#253#12'NW'#25#24#228'@'#18#204#140#12'<'#9#162#12#210#210#130'@=l' + +#160'('#16#0#8' '#156#22#128'|'#193#2#244#129#128#160#8#195#163'O?'#24#4#196 + +#197#225'rl'#10'<'#12#172'rl'#12#238'E~'#12'w'#254'=f'#216#183#244#12#216#18 + +'yv&'#6'f~'#22#6#9#23'^'#134#127#236'`'#7#241#1#4#16#214' '#130#135#245#175 + +'_'#12#23#30'2HJ'#10#131'-'#0#8' '#188'A'#196#195#205#197' '#2'L'#25'L@'#131'8X' + +#216#24#184#152'A'#185#154#139#225#215'/F'#134#175#31#190'1p|'#255#202' /+' + +#197#240#245#235#15#134'/_'#190#3#197#127#3#217#223#193'E'#197#175'_'#127'@' + +#198'|'#1#8' '#156#22#220#184#243#144#225#220#149'['#12#14#22#134#12#188#159 + +#222'3||'#0#12#215#207'_'#25#254#3#13#250#249#238#19#3#203#235#23#12#158#246 + +'V'#192'L'#200#198#240#7'X'#176#129#240#191#127#255#24'~'#255#6#250#248#251 + +'o'#134#191'@_'#2's'#242'/'#128#0#194#176#0#148#129#166#205#152#205' ,.'#197 + +'`'#172#171#206'p'#251#222'#'#6#3'5y'#6#158#127#191#25'n]'#187#201'p'#237#226 + +#21#6#150'Oo'#24#2#156'-'#25#196#132#249#193#25#242#31#158'Z'#17' '#128'P' + +#226#128#137#137#153#161#180#188#154'A'#203#216#142#193#216'@'#151#225#212 + +#133'k'#12'"'#2#220#12#186#234'J@'#23#253#5#7#155#188#188'<'#216'Pd'#0'r=##+' + +#3'6'#0#16'@p'#11#238#221'{'#2#166#223#190#253#192#160#207#203#207#176'i'#251 + +'^'#6#3']-'#6#11#19#3#20#13#31'>}F'#243#241'O'#134#237#219#182'2'#196'D'#199 + +#192#205'@'#6#0#1#196'X^>'#9#197#127#239#223#191'f8xx+'#216#149#194#192'\' + +#140#230'X'#12#0#10#29'MM'#19'`'#10#18'G'#17'ws'#211'eprr`'#4#8' '#176#246 + +#189'{'#247#147#219#180#192#11'@'#22#0#4#16'#'#249#205#22#226#0'@'#128#1#0'R' + ,#186#239#253'E'#255#199#222#0#0#0#0'IEND'#174'B`'#130 +]); +LazarusResources.Add('tkprintsetupdialog','PNG',[ + #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#24#0#0#0#24#8#6#0#0#0#224'w='#248#0 + +#0#0#4'gAMA'#0#0#177#142'|'#251'Q'#147#0#0#0' cHRM'#0#0'z%'#0#0#128#131#0#0 + +#249#255#0#0#128#232#0#0'u0'#0#0#234'`'#0#0':'#151#0#0#23'o'#151#169#153#212 + +#0#0#5#227'IDATx'#156'b'#252#255#255'?'#3'y`?'#19#144'`'#7'b^ '#22#1'bq('#27 + +#4'>'#1#241#11' ~'#3#16'@,'#251#246#29#248#191'k'#215'e'#130#198'111'#194'1#' + +'##'#3'33'#19#3';;'#11#3'//'#7#131#136#8#15#131#176'07'#3#215#127#22#6#166 + +''''#255#24'Dx'#4#25'$D?Fr'#219#255'?'#14#16'@, '#195#195#211#146#240#26#14 + +'4'#143#129#9'd('#19#136'f'#0'['#0#18'S'#191'u'#144#225#169#158'#'#131#216 + +#179'+'#12'w3_00'#127#254#201#192'&'#207#205#240'W'#253';'#3'w'#247#255#31'@' + +#173#172#0#1#196#2'2'#224#228#205'/'#184']'#206#8'R'#197#200#192#205#193#196 + +#192#3#196#28'l'#140#12#236'?'#255'2X'#254#186#206'p'#244#212'U'#6'ku9'#134 + +#213#133#187#25#4'/'#241'2'#200#240'I2'#252#229'cax'#225#246#159#225#243'E' + +#254#245#250#250#31#229#1#2#8'l'#193#229#7'_qZ'#192#6'4'#156#159#155#153'AZ' + +#152#133#129#159#139#149'Ax'#227'S'#6#193'G?'#24#30#165#170'2XgJ3'#156'\t'#11 + +#232'B'#6#6'i'#14'q'#6'fA6'#6#134'.]'#134#143#31'.3'#176#255#249#11#210#254 + +#13' '#128#192#22#240'>'#220#138#211#2'..6'#6#17'q'#1#6'9q'#9#134'giG'#24#248 + +'nK2'#8#7'j2H'#8'}c'#248#246#225'7'#195#181#246#19#12#6#204#170#12#204#194'l' + +#12#130'U'#210#12#247'Y'#238'3'#188'}'#251#133'A@'#0#28#223#223#0#2#8'lAGG.V' + +#195'?||'#207#240#239#223'_'#6#22#22'f'#6'66V'#134#244'+]'#12'&'#28'1`'#185 + +#255#191#248#25'N'#230#237'`P'#248','#206#192'-'#206#195#192#31','#207' '#18 + +#169#15'NN'#199#143'/b'#144#147#3#251#224#7'@'#0#177#192#12'{'#240#224#14#134 + +#5'?'#127#255'dPTP'#134#164#26'&f'#134#223#255#255'20'#3#225#223#183'?'#25 + +#222#205#189#203#192'p'#228#19#131'8'#147'0'#3#183#163'8'#131'h'#141'2'#195 + +#183'o'#239#129#230'1'#156#225#190#198#240'n'#31'0>.~'#7'G' + +#23'@'#0#161#248#0'T'#178#254#250#253#155#225#243#151#143#12'/^'#191'f'#16 + +#145#16'ex'#246#226'9'#3#23''''#27'0'#243#240'3'#216'%'#218'2'#240'iK1|'#226 + +'fg'#248','#247#150#225#246#149#135#12#26#26#230#12#191#24#255'2x'#244#6'1'#8 + +#11#137'1'#188'{'#247#14#232#243#219#12#138#138'`'#183#127#4#8' '#140'8'#248 + +#245#235#7#195#253#7'w'#25#222#0#195#127#215#238'}@K'#129'^'#230#230#0#230'L' + +#30#6#17'e>'#134#207#255#238'1'#252'y'#255#151#225#219#211'_'#12'?'#128#233 + +#253#205#149#205#12#31'8'#213#24'~'#255#250#5't'#8'?'#195#251#247#160'`'#254 + +#200' ))'#12#182#0' '#128'0,'#248#3',CXYY'#25#244#244't'#24'n'#221#190#203 + +#192#2'L'#207#172',l'#192#224'a'#1#198#209#127#6'&'#150#223#12#255#129#153#8 + +#232'Q'#6#21'eu'#6#1'M'#15#134#239'/_'#1#227#227'9'#208'q'#191#25#190'~'#253 + +#14'.*~'#253#250#3#142'V'#128#0'B'#177#0'd'#240#206'];'#128'.'#251#9#230#203 + +#203'H0'#128#162#10'\<3Ah'#6#6'Hjb'#4#6#231#219#215'/'#25#166'L'#157#10#204 + +'Xl'#12#22'f'#22#192#220#251#15'h'#241'_'#134#239#223#127'3'#252#253#11#202 + +'7'#142#191#0#2#8#197#2'I'#9'I'#134'g'#207'_0|'#251#250#133'AS['#147#225#210 + +#165'k'#232#30'D'#1#250#250#218#12#215#174'\'#3#6#159'0'#131#188#188'<'#208 + +#213#191'0'#212#0#4#16#138#5'L'#192#242'FCC'#131'a'#214#172#185#12#206#174 + +#206#12#188#252#2'x-'#224#227#229'fX'#184'p9CFj2'#176#172#194'Z(0'#0#4#16#220 + +#130'{'#247#158#128'ie'#5'5'#134#142#230'f'#134#163''''#142#130'k'#173#223 + +#191#255#128'#'#240'/'#176'T'#5#149'9'#140'@G'#128#202#27'6`p'#254#3#6'Wk}=' + +#131#162#146'2'#195#213'k'#152#133'%'#8#0#4#16#216#130#138#138#201#24#18'r' + +#178'Z'#12#220'\'#236#12#191#129'9'#249#215#239'_'#12#255#128#145#255#31#236 + +'K&p\'#177#178#178#0'K'#207'_'#12#251#15#222#5'c\'#0' '#128#192'1'#182'w'#239 + ,'~r'#155#22'x'#129#147#147#3'#@'#0'1'#146#223'l!'#14#0#4#24#0'/h'#237#236'7[' + +#12#214#0#0#0#0'IEND'#174'B`'#130 +]); diff --git a/components/kcontrols/source/khexeditordesign.pas b/components/kcontrols/source/khexeditordesign.pas new file mode 100755 index 000000000..518bdf39a --- /dev/null +++ b/components/kcontrols/source/khexeditordesign.pas @@ -0,0 +1,36 @@ +unit khexeditordesign; + +{$include kcontrols.inc} + +interface + +procedure Register; + +implementation + +{$IFNDEF FPC} + {$R *.dcr} +{$ENDIF} + +uses + Classes, KControls, KDialogs, KHexEditor +{$IFDEF FPC} + , LResources +{$ENDIF} + ; + +procedure Register; +begin + RegisterComponents('TK', [ + TKHexEditor, + TKPrintPreview, + TKPrintSetupDialog, + TKPrintPreviewDialog + ]); +end; + +{$IFDEF FPC} +initialization + {$i khexeditordesign.lrs} +{$ENDIF} +end. diff --git a/components/kcontrols/source/khexeditorlaz.lpk b/components/kcontrols/source/khexeditorlaz.lpk new file mode 100755 index 000000000..03a760817 --- /dev/null +++ b/components/kcontrols/source/khexeditorlaz.lpk @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/kcontrols/source/khexeditorlaz.pas b/components/kcontrols/source/khexeditorlaz.pas new file mode 100644 index 000000000..57ad1b886 --- /dev/null +++ b/components/kcontrols/source/khexeditorlaz.pas @@ -0,0 +1,22 @@ +{ This file was automatically created by Lazarus. Do not edit! + This source is only used to compile and install the package. + } + +unit KHexEditorLaz; + +interface + +uses + KControls, khexeditordesign, KDialogs, KFunctions, KGraphics, KHexEditor, + KPrintPreview, KPrintSetup, KWideWinProcs, LazarusPackageIntf; + +implementation + +procedure Register; +begin + RegisterUnit('khexeditordesign', @khexeditordesign.Register); +end; + +initialization + RegisterPackage('KHexEditorLaz', @Register); +end. diff --git a/components/kcontrols/source/kicon.pas b/components/kcontrols/source/kicon.pas new file mode 100755 index 000000000..e156ac994 --- /dev/null +++ b/components/kcontrols/source/kicon.pas @@ -0,0 +1,2607 @@ +{ @abstract(This unit provides an advanced Windows icon management + i.e. replacement for the Graphics.TIcon component) + @author(Tomas Krysl (tomkrysl@tkweb.eu)) + @created(9 Jan 2005) + @lastmod(20 Jun 2010) + + Copyright © 2005 Tomas Krysl (tomkrysl@@tkweb.eu)

+ + The purpose of the TKIcon component is to replace and expand the standard + TIcon component provided by VCL. The TKIcon component is not based on Windows + icon functions, but manages the icon structures by itself. +
    + Major features are: +
  • 32-bit icons/cursors with alpha channel supported
  • +
  • correct rendering in all 32-bit Windows platforms
  • +
  • optional rendering of all icon/ cursors subimages
  • +
  • icons/cursors can be stretched when drawn
  • +
  • multiple rendering styles
  • +
  • loading from file/stream, HICON, module resources, file associations
  • +
  • saving to file/stream
  • +
  • icon image manipulation (inserting/deleting/cropping/enlarging)
  • +
  • full TPicture integration (only TPicture.Icon can't be used)
  • +
+ + License:
+ This code is distributed as a freeware. You are free to use it as part + of your application for any purpose including freeware, commercial and + shareware applications. The origin of this source code must not be + misrepresented; you must not claim your authorship. You may modify this code + solely for your own purpose. Please feel free to contact the author if you + think your changes might be useful for other users. You may distribute only + the original package. The author accepts no liability for any damage + that may result from using this code. } + +unit KIcon; + +{$include kcontrols.inc} +{$IFNDEF TKICON_REGISTER} + {$WEAKPACKAGEUNIT ON} +{$ENDIF} + +interface + +{$IFDEF USE_WINAPI} + +uses + Windows, SysUtils, Classes, Graphics, KGraphics +{$IFDEF USE_PNG_SUPPORT} + {$IFDEF FPC} + , fpImage, GraphType, IntfGraphics + {$ELSE} + , PngImage + {$ENDIF} +{$ENDIF}; + +resourcestring + { @exclude } + SVIcons = 'Icons'; + { @exclude } + SVCursors = 'Cursors'; + { @exclude } + SIconAllocationError = 'Error while allocating icon data'; + { @exclude } + SIconBitmapError = 'Invalid icon bitmap handles'; + { @exclude } + SIconFormatError = 'Invalid icon format'; + { @exclude } + SIconResourceError = 'Invalid icon resource'; + { @exclude } + SIconIndexError = 'Invalid icon resource index'; + { @exclude } + SIconInvalidModule = 'Invalid module or no icon resources'; + { @exclude } + SIconResizingError = 'Error while resizing icon'; + { @exclude } + SIconAssocResolveError = 'Error while resolving associated icon'; + +type +{$IFDEF USE_PNG_SUPPORT} + { @exclude } + TKIconPngObject = TKPngImage; +{$ELSE} + { @exclude } + TKIconPngObject = TMemoryStream; //used to store compressed PNG stream +{$ENDIF} + + { @abstract(Icon file header) +
    + Members: +
  • idReserved - always 0
  • +
  • idType - 1=icon, 2=cursor
  • +
  • idCount - total number of icon images in file
  • +
+ } + TKIconHeader = packed record + idReserved: Word; + idType: Word; + idCount: Word; + end; + + { Pointer to the icon file header structure } + PKIconHeader = ^TKIconHeader; + + { @abstract(Helper structure identifying attributes that are different for + icons and cursors) +
    + Members: +
  • wPlanes - for icons: amount of image planes - I think that this is always 1
  • +
  • wBitCount - for icons: image color resolution
  • +
  • wX - for cursors: hot spot horizontal coordinate
  • +
  • wY - for cursors: hot spot vertical coordinate
  • +
+ } + TKIconCursorDirInfo = packed record + case Integer of + 0: ( + wPlanes: Word; + wBitCount: Word; + ); + 1: ( + wX: Word; + wY: Word; + ); + end; + + { @abstract(Icon/cursor directory entry. This structure decribes each + icon/cursor image. These structures describing all images immediately follow + the @link(TKIconHeader) structure in the icon file. After these the bitmap data + for all images are stored (TBitmapInfoHeader, palette data, bitmap bits - XOR, AND).) +
    + Members: +
  • Width - image width
  • +
  • Height - image height
  • +
  • ColorCount - number of entries in palette table
  • +
  • Reserved - not used
  • +
  • Info - different for icons/cursors
  • +
  • dwBytesInRes - total number bytes in the image including + pallette data, XOR bits, AND bits and bitmap info header
  • +
  • dwImageOffset - position of image as offset from the beginning of file
  • +
+ } + TKIconCursorDirEntry = packed record + Width: Byte; + Height: Byte; + ColorCount: Byte; + Reserved: Byte; + Info: TKIconCursorDirInfo; + dwBytesInRes: Longint; + dwImageOffset: Longint; + end; + + { Pointer to the icon/cursor directory entry } + PKIconCursorDirEntry = ^TKIconCursorDirEntry; + + { Helper structure to typecast cursor hot spot coordinates } + TKCursorHotSpot = packed record + xHotSpot: Word; + yHotSpot: Word; + end; + + { Pointer to the cursor hot spot structure } + PKCursorHotSpot = ^TKCursorHotSpot; + + { Helper structure for cursor specific data in resource file } + TKCursorDir = packed record + Width: Word; + Height: Word; + end; + + { Helper structure for icon specific data in resource file } + TKIconResdir = packed record + Width: Byte; + Height: Byte; + ColorCount: Byte; + Reserved: Byte; + end; + + { Helper structure merging icon and cursor specific data } + TKIconCursorInfo = packed record + case Integer of + 0: (Icon: TKIconResdir); + 1: (Cursor: TKCursorDir); + end; + + { @abstract(Icon/cursor directory entry as found in resource files) +
    + Members: +
  • Info - structure that merges icon/cursor specific data
  • +
  • wPlanes - not used = 0
  • +
  • wBitCount - not used = 0
  • +
  • dwBytesInRes - total number of bytes in the image including + pallette data, XOR bits, AND bits and bitmap info header
  • +
  • wEntryName - icon/cursor entry name. This number identifies the + particular icon image in a resource file (images are stored under ICONENTRY + key)
  • +
+ } + TKIconCursorDirEntryInRes = packed record + Info: TKIconCursorInfo; + wPlanes: Word; + wBitCount: Word; + dwBytesInRes: Longint; + wEntryName: Word; + end; + + { Pointer to the icon/cursor resource file directory entry } + PKIconCursorDirEntryInRes = ^TKIconCursorDirEntryInRes; + + { Helper structure to access resource data } + TKIconCursorInRes = packed record + IH: TKIconHeader; + Entries: array [0..MaxInt div SizeOf(TKIconCursorDirEntryInRes) - 2] of TKIconCursorDirEntryInRes; + end; + + { Pointer to the helper structure } + PKIconCursorInRes = ^TKIconCursorInRes; + + { Controls how the image should be aligned when they are beeing resized } + TKIconAlignStyle = ( + { image remains aligned to the top-left corner } + asNone, + { image will be centered within the new boundary rectangle } + asCenter + ); + + { Specifies the width and height of an icon or cursor image } + TKIconDimension = record + Width, + Height: Integer; + end; + + { @abstract(Specifies the GDI handles for one icon/cursor image) +
    + Members: +
  • hXOR - handle to the color bitmap - icon image
  • +
  • hAND - handle to the monochrome bitmap - icon image mask
  • +
+ } + TKIconHandles = record + hXOR, + hAND: HBITMAP; + end; + + { @abstract(Represents the internal data structure describing each icon/cursor image) +
    + Members: +
  • Width - image width
  • +
  • Height - image height
  • +
  • Bpp - image color resolution
  • +
  • BytesInRes - total image data size
  • +
  • HotSpot - hot spot for a cursor
  • +
  • iXOR - pointer to the color bitmap info header + palette
  • +
  • iXORSize - size of iXOR data
  • +
  • pXOR - pointer to the color bitmap bits
  • +
  • pXORSize - size of pXOR data
  • +
  • hXOR - handle to the color bitmap - is always a DIB section
  • +
  • pAND - pointer to the monochrome (mask) bitmap bits
  • +
  • pANDSize - size of pAND data
  • +
  • hAND - handle to the monochrome bitmap - is always a DIB section
  • +
  • PNG - holds the PNG image
  • +
+ } + TKIconData = record + Width: Integer; + Height: Integer; + Bpp: Integer; + BytesInRes: Integer; + Offset: Integer; + HotSpot: TPoint; + iXOR: PBitmapInfo; + iXORSize: Integer; + pXOR: Pointer; + pXORSize: Integer; + hXOR: HBITMAP; + pAND: Pointer; + pANDSize: Integer; + hAND: HBITMAP; + IsPNG: Boolean; + PNG: TKIconPngObject; + end; + + { Pointer to the internal image description structure } + PKIconData = ^TKIconData; + + { Specifies how the icon image(s) should be rendered. This feature can be used + along with the MaskFromColor method to implement a ‘color picker’ for a new mask construction. } + TKIconDrawStyle = ( + { paint normally } + idsNormal, + { paint without applying the mask - color bitmap only } + idsNoMask, + { paint only the mask - monochrome bitmap only } + idsMaskOnly, + { paint only the alpha channel as grayscale image - only for 32 bit icon bitmaps else paint as with idsNoMask style } + idsAlphaChannel + ); + + { KIcon main class. } + TKIcon = class(TGraphic) + private + FAlignStyle: TKIconAlignStyle; + FBpp: Integer; + FCreating: Boolean; + FCurrentIndex: Integer; + FCursor: Boolean; + FDisplayAll: Boolean; + FDisplayHorz: Boolean; + FIconCount: Integer; + FIconData: array of TKIconData; + FIconDrawStyle: TKIconDrawStyle; + FInHandleBpp: Integer; + FInHandleFullAlpha: Boolean; + FMaxHeight: Integer; + FMaxWidth: Integer; + FOptimalIcon: Boolean; + FOverSizeWeight: Single; + FRequestedSize: TKIconDimension; + FSpacing: Integer; + FStretchEnabled: Boolean; + function GetDimensions(Index: Integer): TKIconDimension; + function GetHandles(Index: Integer): TKIconHandles; + function GetHeights(Index: Integer): Integer; + function GetHotSpot(Index: Integer): TPoint; + function GetIconData(Index: Integer): TKIconData; + function GetWidths(Index: Integer): Integer; + procedure SetCurrentIndex(Value: Integer); + procedure SetDimensions(Index: Integer; Value: TKIconDimension); + procedure SetDisplayAll(Value: Boolean); + procedure SetDisplayHorz(Value: Boolean); + procedure SetHandles(Index: Integer; Value: TKIconHandles); + procedure SetHeights(Index: Integer; Value: Integer); + procedure SetHotSpot(Index: Integer; Value: TPoint); + procedure SetInHandleBpp(Value: Integer); + procedure SetIconDrawStyle(Value: TKIconDrawStyle); + procedure SetOptimalIcon(Value: Boolean); + procedure SetOverSizeWeight(Value: Single); + procedure SetRequestedSize(Value: TKIconDimension); + procedure SetSpacing(Value: Integer); + procedure SetStretchEnabled(Value: Boolean); + procedure SetWidths(Index: Integer; Value: Integer); + protected + { Overriden method - see Delphi help. Calls @link(Update) method. } + procedure Changed(Sender: TObject); override; + { Overriden method - see Delphi help. } + procedure Draw(ACanvas: TCanvas; const Rect: TRect); override; + { Overriden method - see Delphi help. } + function GetEmpty: Boolean; override; + { Overriden method - see Delphi help. } + function GetHeight: Integer; override; + { Overriden method - see Delphi help. } + function GetTransparent: Boolean; override; + { Overriden method - see Delphi help. } + function GetWidth: Integer; override; + { Copies the bitmaps stored in Handles to the icon image identified by Index. + If OrigBpp is True, the color resolution for the color bitmap remains unchanged, + otherwise the value of InHandleBpp will be used. } + procedure LoadHandles(Index: Integer; const Handles: TKIconHandles; OrigBpp: Boolean); + { Overriden method - see Delphi help. } + procedure SetHeight(Value: Integer); override; + { Overriden method - see Delphi help. } + procedure SetTransparent(Value: Boolean); override; + { Overriden method - see Delphi help. } + procedure SetWidth(Value: Integer); override; + { Updates @link(MaxWidth), @link(MaxHeight) and @link(CurrentIndex) + properties accordingly. } + procedure Update; dynamic; + { Resizes an icon image identified by Index to new dimensions stored in Value. + The AlignStyle property controls the image alignment within the new rectangle. } + procedure UpdateDim(Index: Integer; Value: TKIconDimension); + public + { Overriden method - see Delphi help. } + constructor Create; override; + { Overriden method - see Delphi help. } + destructor Destroy; override; + { Adds a new image to the end of the internal image list. You should always + specify valid color and mask bitmap handles else an exception will occur. } + procedure Add(const Handles: TKIconHandles); + { Overriden method - see Delphi help. } + procedure Assign(Source: TPersistent); override; + { Clears all images so that the instance contains no icon/cursor. } + procedure Clear; {$IFDEF FPC}override{$ELSE}dynamic{$ENDIF}; + { Copies the icon image into an alpha bitmap identified by Bitmap. + Icon image is copied to the alpha bitmap. It icon has alpha channel + it is copied as well. + Bitmap size will always be matched to the icon image. } + procedure CopyToAlphaBitmap(Index: Integer; Bitmap: TKAlphaBitmap); + { Copies the icon image into a bitmap identified by Bitmap. Both color + and mask image is copied to preserve true transparency. You can use this + to pass to Glyph properties (e.g. TSpeedButton). Bitmap properties will + always be matched to the icon image. For 32bpp icon images, + alpha channel is copied as well. } + procedure CopyToBitmap(Index: Integer; Bitmap: TBitmap); + {$IFDEF USE_PNG_SUPPORT} + { Copies the icon image into a png image identified by Png. + It is saved always in truecolor format with alpha channel (32bpp). + Png size will always be matched to the icon image. } + procedure CopyToPng(Index: Integer; Png: TKPngImage); + {$ENDIF} + { Creates an icon handle for use with Win32 API icon functions. The image + identified by Index will be used for this handle. If DisplayAll is False + and Index is out of range, CurrentIndex will be used instead. } + function CreateHandle(Index: Integer): HICON; + { Deletes an image identified by Index from the internal image list. } + procedure Delete(Index: Integer); + { Inserts an image at the position identified by Index into the internal + image list. The existing images will be preserved and shifted accordingly. } + procedure Insert(Index: Integer; const Handles: TKIconHandles); + {$IFNDEF FPC} + { Overriden method - see Delphi help. Does nothing for icons/cursors. } + procedure LoadFromClipboardFormat(AFormat: Word; AData: THandle; + APalette: HPALETTE); override; + { Loads the icon from the module associated with the file identified by FileName + (DefaultIcon registry key). If no association can be found for the file, + an exception will be raised and the function will try to load FileName + as if it was a module itself. } + {$ENDIF} + procedure LoadFromAssocFile(const FileName: string); + { Loads the icon from the module associated with the file extension identified + by Extension (DefaultIcon registry key). The Extension parameter should + contain the leading period ('.'). If no association can be found for that + extension, an exception will be triggered. } + procedure LoadFromAssocExtension(const Extension: string); + { Loads the icon from Win32 API icon handle. Please keep in mind that icon bitmaps + can't be loaded as DIBs because they are already converted to DDBs when + accessible through HICON. So it is impossible to load the icon in it's + native format (e.g. as stored in an *.ico file) from HICON. This function + has been introduced only to complete the loading schemes of this class + and you should rather use another LoadFrom... methods. The behavior of this + function can be controlled via the InHandleBpp and InHandleFullAlpha properties. + It is not recommended to use this function in new projects. } + procedure LoadFromHandle(Handle: HICON); + { Loads the icon from resources of a module identified by ModuleName. + A valid icon resource must be specified by ID, otherwise + an exception occurs. This function uses the LoadLibrary API function, so + it is recommended to use the LoadFromResourceX functions to load multiple + icons from the same module. ID is of type Word so it can’t exceed 65535. } + procedure LoadFromModule(const ModuleName: string; ID: Word); overload; + { Does the same thing, but with resource ID specified as string. Let's suppose + ID = 123. Here you can pass it as a string '#123'. } + procedure LoadFromModule(const ModuleName, ResName: string); overload; + { This function does the same as @link(LoadFromModule), but the icon resource + is specified by index here. The index stands for the n-th icon stored + in the module resources. So, LoadFromModule('dummy.exe', 'MAINICON') would + produce the same results as LoadFromModuleByIndex('dummy.exe', 0), + provided 'MAINICON' is the first icon resource in 'dummy.exe'. } + procedure LoadFromModuleByIndex(const ModuleName: string; Index: Integer); + { Loads the icon from resources of a module instance identified by Instance. + Further behavior corresponds to @link(LoadFromModule) with resource ID + specified as integer. } + procedure LoadFromResource(Instance: HINST; ID: Word); overload; + { Loads the icon from resources of a module instance identified by Instance. + Further behavior corresponds to @link(LoadFromModule) with resource ID + specified as string. } + procedure LoadFromResource(Instance: HINST; const ResName: string); overload; + { Loads the icon from resources of a module instance identified by Instance. + Further behavior corresponds to @link(LoadFromModuleByIndex). } + procedure LoadFromResourceByIndex(Instance: HINST; Index: Integer); + { Loads the icon from the stream. Parses the *.ico file structure. + An overriden method. } + procedure LoadFromStream(Stream: TStream); override; + { Makes it possible to create a new mask bitmap for the image identified by Index. + The new monochrome mask bitmap will be created from the color bitmap. + Pixels of the color bitmap that match Color will be masked by the new mask, + other pixels will be unmasked. If the Color parameter contains alpha channel, + you should set HasAlpha to True to perform comparison with the alpha channel. + Otherwise, only the red, green and blue channels will be compared. } + procedure MaskFromColor(Index: Integer; Color: TColor; HasAlpha: Boolean = False); + {$IFNDEF FPC} + { Overriden method - see Delphi help. Does nothing for icons/cursors. } + procedure SaveToClipboardFormat(var Format: Word; var Data: THandle; + var APalette: HPALETTE); override; + {$ENDIF} + { Saves the icon to the stream. Assembles the *.ico file structure. An overriden method. } + procedure SaveToStream(Stream: TStream); override; + { Controls the icon image resizing which is performed by the UpdateDim method. } + property AlignStyle: TKIconAlignStyle read FAlignStyle write FAlignStyle; + { Specifies the index of the currently displayed icon image. + If no image is loaded (no icon), the value of CurrentIndex is -1. } + property CurrentIndex: Integer read FCurrentIndex write SetCurrentIndex; + { Indicates whether the instance of this class represents a cursor (True) or an icon (False). } + property Cursor: Boolean read FCursor write FCursor; + { Specifies whether all icon images (True) or a single subimage should be + drawn (False). When True, all available icon images will be rendered. } + property DisplayAll: Boolean read FDisplayAll write SetDisplayAll; + { Specifies how the images should be drawn when @link(DisplayAll) is True. + If True, the images will be drawn horizontally aligned. If False, + the images will be drawn vertically aligned. } + property DisplayHorz: Boolean read FDisplayHorz write SetDisplayHorz; + { Makes it possible to read/modify the size of an icon image. } + property Dimensions[Index: Integer]: TKIconDimension read GetDimensions write SetDimensions; + { Makes it possible to read/modify icon image bitmaps (color and mask bitmap). + Bitmaps that you pass will be copied and remain unchanged. When reading + original bitmap handles are returned and thus must not be modified or released. } + property Handles[Index: Integer]: TKIconHandles read GetHandles write SetHandles; + { Makes it possible to read/modify the height of an icon image. } + property Heights[Index: Integer]: Integer read GetHeights write SetHeights; + { For a cursor, this property contains the hot spots for all cursor images. } + property HotSpot[Index: Integer]: TPoint read GetHotSpot write SetHotSpot; + { Returns the number of images found in this instance. } + property IconCount: Integer read FIconCount; + { Makes it possible to read the internal data structure of each icon image. + A copy of the structure is returned but the pointers or handles are original + (no copies are created) and thus must not be modified or released. } + property IconData[Index: Integer]: TKIconData read GetIconData; + { Affects the icon image rendering. } + property IconDrawStyle: TKIconDrawStyle read FIconDrawStyle write SetIconDrawStyle; + { Specifies the color resolution a DIB should have after converted from a DDB + that has been passed to the LoadHandles method. } + property InHandleBpp: Integer read FInHandleBpp write SetInHandleBpp; + { Determines whether a DIB with 32 bits per pixel should have full visibility + (alpha channel of each pixel set to 0xFF) after converted from a DDB + that has been passed to the LoadHandles method. The alpha channel values will + be only set to 0xFF when the current alpha channel of every pixel is zero. } + property InHandleFullAlpha: Boolean read FInHandleFullAlpha write FInHandleFullAlpha; + { Returns the height of the image that has the maximum height of all icon images. + When @link(DisplayAll) is True and @link(DisplayHorz) is False, returns the + total height of all images and spaces between them (specified by @link(Spacing)). } + property MaxHeight: Integer read FMaxHeight; + { Returns the width of the image that has the maximum width of all icon images. + When both @link(DisplayAll) and @link(DisplayHorz) is True, returns the + total width of all images and spaces between them (specified by @link(Spacing)). } + property MaxWidth: Integer read FMaxWidth; + { This property applies only when DisplayAll is False. It determines whether + the icon image corresponding to the RequestedSize property and the current + display mode color resolution (True) or the subimage specified by CurrentIndex + (False) should be displayed. } + property OptimalIcon: Boolean read FOptimalIcon write SetOptimalIcon; + { Controls the decision threshold for the optimal image when OptimalIcon is True. + The bigger the value is, the less is the probability a subimage greater than + RequestedSize will be selected. This value is big enough by default so that + almost always a smaller image will be selected if none with the exact size is found. } + property OverSizeWeight: Single read FOverSizeWeight write SetOverSizeWeight; + { Specifies the preferred image size when OptimalIcon is True. + When OverSizeWeight is small, a greater subimage may be often selected. } + property RequestedSize: TKIconDimension read FRequestedSize write SetRequestedSize; + { Specifies the spacing between icon images when @link(DisplayAll) is True. } + property Spacing: Integer read FSpacing write SetSpacing; + { Specifies whether icon images can be stretched when drawn. This property + was introduced perhaps only for backward compatibility with Graphics.TIcon. } + property StretchEnabled: Boolean read FStretchEnabled write SetStretchEnabled; + { Makes it possible to read/modify the width of an icon image. } + property Widths[Index: Integer]: Integer read GetWidths write SetWidths; + end; + + { This class is necessary because of the TPicture streaming. } + TIcon = class(TKIcon); + +{ Creates a bitmap from an icon object stored in application resources. } +function CreateBitmapFromResIcon(const ResName: string; ResType: PChar = RT_ICON): TBitmap; + +{ Creates an alpha bitmap from an icon object stored in application resources. } +function CreateAlphaBitmapFromResIcon(const ResName: string; ResType: PChar): TKAlphaBitmap; + +{ Returns the str1ucture containing hXOR and hAND bitmaps. } +function MakeHandles(hXOR, hAND: HBITMAP): TKIconHandles; + +{ Returns the total number of resources of a type specified by ResType + in a module identified by Instance. } +function GetModuleResourceCount(Instance: HINST; ResType: PChar): Integer; + +{ Returns the total number of HW-independent icon resources + in a module identified by Instance. } +function GetModuleIconCount(Instance: HINST): Integer; overload; + +{ Returns the total number of HW-independent icon resources + in a module identified by ModuleName. } +function GetModuleIconCount(const ModuleName: string): Integer; overload; + +{ Integrates KIcon into TPicture. } +procedure RegisterKIcon; + +{ Removes KIcon from TPicture. } +procedure UnregisterKIcon; + +{$ENDIF} + +implementation + +{$IFDEF USE_WINAPI} + +uses + Math, Registry, KFunctions; + +type + TKMaskBitmapInfo = packed record + Header: TBitmapInfoHeader; + Black, + White: TRGBQuad; + end; + +procedure FreeSubimage(PID: PKIconData); +begin + FreeMem(PID.iXOR); + if PID.hXOR <> 0 then DeleteObject(PID.hXOR); + if PID.hAND <> 0 then DeleteObject(PID.hAND); + PID.PNG.Free; + FillChar(PID^, SizeOf(TKIconData), 0); +end; + +function CalcByteWidth(Width, Bpp: Integer): Integer; +begin + Result := DivUp(Width * Bpp, SizeOf(LongWord) shl 3) * SizeOf(LongWord); +end; + +function CalcBitmapSize(Width, Height, Bpp: Integer): Integer; +begin + Result := CalcByteWidth(Width, Bpp) * Height; +end; + +procedure CalcByteWidths(Width, Bpp: Integer; out XORWidth, ANDWidth: Integer); +begin + XORWidth := CalcByteWidth(Width, Bpp); + ANDWidth := CalcByteWidth(Width, 1); +end; + +procedure CalcBitmapSizes(Width, Height, Bpp: Integer; out XORSize, ANDSize: Integer); +begin + XORSize := CalcBitmapSize(Width, Height, Bpp); + ANDSize := CalcBitmapSize(Width, Height, 1); +end; + +function GetPaletteSize(Bpp: Integer): Integer; +begin + if Bpp <= 8 then + Result := 1 shl Bpp + else + Result := 0; +end; + +procedure QueryBitmapBits(DC: HDC; hBmp: HBITMAP; var Bits: Pointer; var Size: Integer); +var + BInfo: Windows.TBitmap; + BI: TBitmapInfo; +begin + GetObject(hBmp, SizeOf(Windows.TBitmap), @BInfo); + Size := CalcBitmapSize(BInfo.bmWidth, BInfo.bmHeight, BInfo.bmBitsPixel); + GetMem(Bits, Size); + FillChar(BI, SizeOf(TBitmapInfo), 0); + with BI.bmiHeader do + begin + biSize := SizeOf(TBitmapInfoHeader); + biWidth := BInfo.bmWidth; + biHeight := BInfo.bmHeight; + biPlanes := 1; + biBitCount := BInfo.bmBitsPixel; + biCompression := BI_RGB; + end; + GetDIBits(DC, hBmp, 0, BInfo.bmHeight, Bits, BI, DIB_RGB_COLORS); +end; + +procedure CreateColorInfo(Width, Height, Bpp: Integer; var BI: PBitmapInfo; var InfoSize: Integer); +begin + InfoSize := SizeOf(TBitmapInfoHeader) + GetPaletteSize(Bpp) * SizeOf(TRGBQuad); + GetMem(BI, InfoSize); + FillChar(BI^, InfoSize, 0); + with BI.bmiHeader do + begin + biSize := SizeOf(TBitmapInfoHeader); + biWidth := Width; + biHeight := Height; + biPlanes := 1; + biBitCount := Bpp; + end; +end; + +procedure CreateMaskInfo(Width, Height: Integer; var BIMask: TKMaskBitmapInfo); +begin + FillChar(BIMask, SizeOf(TKMaskBitmapInfo), 0); + with BIMask.Header do + begin + biSize := SizeOf(TBitmapInfoHeader); + biWidth := Width; + biHeight := Height; + biPlanes := 1; + biBitCount := 1; + end; + Cardinal(BIMask.Black) := clBlack; + Cardinal(BIMask.White) := clWhite; +end; + +function CreateMonochromeBitmap(Width, Height: Integer): HBITMAP; +begin + Result := GDICheck(CreateBitmap(Width, Height, 1, 1, nil)); +end; + +procedure MaskOrBitBlt(ACanvas: TCanvas; X, Y, Width, Height: Integer; + DC_XOR, DC_AND: HDC; BM_XOR, BM_AND: HBITMAP; + XORBits: PKColorRecs; XORSize: Integer; + ANDBits: PBytes; ANDSize: Integer; + Bpp: Integer; Style: TKIconDrawStyle); +var + I, J, K, LAnd: Integer; + Alpha, ByteMask: Byte; + FreeBits: Boolean; + Q: PBytes; + Ps, Pd: PKColorRecs; + BMSrc, BMDest: TKAlphaBitmap; + R: TRect; +begin + if Style <> idsMaskOnly then + begin + BMSrc := TKAlphaBitmap.Create; + try + BMDest := TKAlphaBitmap.Create; + try + R := Rect(X, Y, X + Width, Y + Height); + BMSrc.SetSize(Width, Height); + if Bpp = 32 then + begin // perform alphablend + if XORBits = nil then + begin + QueryBitmapBits(DC_XOR, BM_XOR, Pointer(XORBits), XORSize); + FreeBits := True; + end else + FreeBits := False; + try + if Style = idsAlphaChannel then + begin + for I := 0 to Height - 1 do + begin + Ps := BMSrc.ScanLine[I]; + K := I * Width; + for J := 0 to Width - 1 do + begin + Alpha := 255 - XORBits[K + J].A; + Ps[J].R := Alpha; + Ps[J].G := Alpha; + Ps[J].B := Alpha; + end; + end; + end else + begin + BMSrc.DrawFrom(ACanvas, R); + for I := 0 to Height - 1 do + begin + Ps := @XORBits[I * Width]; + Pd := BMSrc.ScanLine[I]; + BlendLine(Ps, Pd, Width); + end + end + finally + if FreeBits then FreeMem(XORBits); + end; + end else + BitBlt(BMSrc.Canvas.Handle, 0, 0, Width, Height, DC_XOR, 0, 0, SRCCOPY); + if Style = idsNormal then + begin + BMDest.SetSize(Width, Height); + BMDest.DrawFrom(ACanvas, R); + if ANDBits = nil then + begin + QueryBitmapBits(DC_XOR, BM_AND, Pointer(ANDBits), ANDSize); + FreeBits := True; + end else + FreeBits := False; + if ANDBits <> nil then + begin + try + LAnd := CalcByteWidth(Width, 1); + Q := ANDBits; + for I := 0 to Height - 1 do + begin + Ps := BMSrc.ScanLine[I]; + Pd := BMDest.ScanLine[I]; + ByteMask := $80; + for J := 0 to Width - 1 do + begin + if Q[J shr 3] and ByteMask <> 0 then + Ps[J] := Pd[J]; + asm + ror ByteMask, 1 + end; + end; + Inc(Cardinal(Q), LAnd); + end; + finally + if FreeBits then FreeMem(ANDBits); + end; + end; + end; + BMSrc.DrawTo(ACanvas, R); + finally + BMDest.Free; + end; + finally + BMSrc.Free; + end; + end else + begin + if DC_AND = 0 then + begin + DC_AND := CreateCompatibleDC(ACanvas.Handle); + try + SelectObject(DC_AND, BM_AND); + BitBlt(ACanvas.Handle, X, Y, Width, Height, DC_AND, 0, 0, SrcCopy); + finally + DeleteDC(DC_AND); + end; + end else + BitBlt(ACanvas.Handle, X, Y, Width, Height, DC_AND, 0, 0, SrcCopy); + end; +end; + +procedure FillAlphaIfNone(Pixels: PKColorRecs; Size: Integer; Alpha: Byte); +var + I: Integer; +begin + Size := Size shr 2; + for I := 0 to Size - 1 do + if Pixels[I].A <> 0 then + Exit; // bitmap has a nonempty alpha channel, don't fill + for I := 0 to Size - 1 do + Pixels[I].A := Alpha; +end; + +function CreateBitmapFromResIcon(const ResName: string; ResType: PChar): TBitmap; +var + Icon: TKIcon; + Stream: TResourceStream; +begin + Result := TBitmap.Create; + Icon := TKIcon.Create; + try + Stream := TResourceStream.Create(HInstance, ResName, ResType); + try + Icon.LoadFromStream(Stream); + Icon.CopyToBitmap(Icon.CurrentIndex, Result); + finally + Stream.Free; + end; + finally + Icon.Free; + end; +end; + +function CreateAlphaBitmapFromResIcon(const ResName: string; ResType: PChar): TKAlphaBitmap; +var + Icon: TKIcon; + Stream: TResourceStream; +begin + Result := TKAlphaBitmap.Create; + Icon := TKIcon.Create; + try + Stream := TResourceStream.Create(HInstance, ResName, ResType); + try + Icon.LoadFromStream(Stream); + Icon.CopyToAlphaBitmap(Icon.CurrentIndex, Result); + finally + Stream.Free; + end; + finally + Icon.Free; + end; +end; + +procedure InternalCopyToAlphaBitmap(ABitmap: TKAlphaBitmap; + BM_XOR: HBITMAP; AndBits: PBytes; Bpp: Integer); +var + I, J, LAnd: Integer; + ByteMask: Byte; + Q: PBytes; + Ps: PKColorRecs; + DC: HDC; +begin + if (ABitmap <> nil) and (AndBits <> nil) and (BM_XOR <> 0) then + begin + DC := CreateCompatibleDC(0); + try + SelectObject(DC, BM_XOR); + BitBlt(ABitmap.Canvas.Handle, 0, 0, ABitmap.Width, ABitmap.Height, DC, 0, 0, SRCCOPY); + LAnd := CalcByteWidth(ABitmap.Width, 1); + Q := ANDBits; + for I := 0 to ABitmap.Height - 1 do + begin + Ps := ABitmap.ScanLine[I]; + ByteMask := $80; + for J := 0 to ABitmap.Width - 1 do + begin + if Q[J shr 3] and ByteMask <> 0 then + Ps[J].A := 0 + else if Bpp < 32 then + Ps[J].A := 255; + asm + ror ByteMask, 1 + end; + end; + Inc(Cardinal(Q), LAnd); + end; + finally + DeleteDC(DC); + end; + end; +end; + +function MakeHandles(hXOR, hAND: HBITMAP): TKIconHandles; +begin + Result.hXOR := hXOR; + Result.hAND := hAND; +end; + +function GetModuleResourceCount(Instance: HINST; ResType: PChar): Integer; + + function EnumIcons(hModule: HINST; lpType, lpName: PChar; dwParam: DWORD): BOOL; stdcall; + begin + Inc(PInteger(dwParam)^); + Result := True; + end; + +begin + Result := 0; + EnumResourceNames(Instance, ResType, @EnumIcons, DWORD(@Result)); +end; + +function GetModuleIconCount(Instance: HINST): Integer; +begin + Result := GetModuleResourceCount(Instance, RT_GROUP_ICON); +end; + +function GetModuleIconCount(const ModuleName: string): Integer; +var + Module: HINST; +begin + Result := 0; + Module := LoadLibraryEx(PChar(ModuleName), 0, LOAD_LIBRARY_AS_DATAFILE); + if Module <> 0 then + begin + try + Result := GetModuleIconCount(Module); + finally + FreeLibrary(Module); + end; + end; +end; + +{ TKIcon } + +constructor TKIcon.Create; +begin + inherited Create; + FCreating := True; + try + Transparent := True; // we are not in Graphics.pas... + finally + FCreating := False; + end; + FAlignStyle := asCenter; + FCursor := False; + FDisplayAll := False; + FIconDrawStyle := idsNormal; + FInHandleBpp := 0; + FInHandleFullAlpha := True; + FIconData := nil; + FOptimalIcon := True; + FOverSizeWeight := 1000.0; // virtually always selects a lower resolution image + FRequestedSize.Width := 32; + FRequestedSize.Height := 32; + FSpacing := 2; + FStretchEnabled := True; + Clear; +end; + +destructor TKIcon.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TKIcon.Add(const Handles: TKIconHandles); +begin + Inc(FIconCount); + SetLength(FIconData, FIconCount); + FillChar(FIconData[FIconCount - 1], SizeOf(TKIconData), 0); + LoadHandles(FIconCount - 1, Handles, True); +end; + +procedure TKIcon.Assign(Source: TPersistent); +var + MS: TMemoryStream; +begin + if (Source = nil) or (Source is TKIcon) then + begin + Clear; + if Source <> nil then + begin + FAlignStyle := TKIcon(Source).AlignStyle; + FCursor := TKIcon(Source).Cursor; + FDisplayAll := TKIcon(Source).DisplayAll; + FIconDrawStyle := TKIcon(Source).IconDrawStyle; + FInHandleBpp := TKIcon(Source).InHandleBpp; + FInHandleFullAlpha := TKIcon(Source).InHandleFullAlpha; + FOptimalIcon := TKIcon(Source).OptimalIcon; + FOverSizeWeight := TKIcon(Source).OverSizeWeight; + FRequestedSize := TKIcon(Source).RequestedSize; + FSpacing := TKIcon(Source).Spacing; + FStretchEnabled := TKIcon(Source).StretchEnabled; + if not TKIcon(Source).Empty then + begin + MS := TMemoryStream.Create; + try + TKIcon(Source).SaveToStream(MS); + MS.Position := 0; + LoadFromStream(MS); + FCurrentIndex := TKIcon(Source).CurrentIndex; + finally + MS.Free; + end; + end else + Changed(Self); + end else + Changed(Self); + Exit; + end; + inherited Assign(Source); +end; + +procedure TKIcon.Changed(Sender: TObject); +begin + Update; + inherited; +end; + +procedure TKIcon.Clear; +var + I: Integer; +begin + if FIconData <> nil then + begin + for I := 0 to FIconCount - 1 do + FreeSubimage(@FIconData[I]); + FIconData := nil; + end; + FIconCount := 0; + Update; +end; + +procedure TKIcon.CopyToAlphaBitmap(Index: Integer; Bitmap: TKAlphaBitmap); +var + ID: TKIconData; +{$IFDEF USE_PNG_SUPPORT} + I, J: Integer; + C: TKColorRec; + {$IFDEF FPC} + IM: TLazIntfImage; + FC: TFPColor; + {$ENDIF} +{$ENDIF} +begin + if (Index >= 0) and (Index < FIconCount) and (Bitmap <> nil) then + begin + ID := FIconData[Index]; + Bitmap.SetSize(ID.Width, ID.Height); + Bitmap.DirectCopy := True; + try + if ID.IsPng then + begin + {$IFDEF USE_PNG_SUPPORT} + {$IFDEF FPC} + IM := ID.PNG.CreateIntfImage; + try + for I := 0 to ID.Width - 1 do + for J := 0 to ID.Height - 1 do + begin + FC := IM.Colors[I, J]; + C.A := FC.alpha; C.B := FC.blue; C.R := FC.red; C.G := FC.green; + Bitmap.Pixel[I, J] := C; + end; + finally + IM.Free; + end; + {$ELSE} + for I := 0 to ID.Width - 1 do + for J := 0 to ID.Height - 1 do + begin + C.Value := ID.PNG.Pixels[I, J]; + C.A := ID.PNG.AlphaScanline[J][I]; + Bitmap.Pixel[I, J] := C; + end; + {$ENDIF} + {$ENDIF} + end else + InternalCopyToAlphaBitmap(Bitmap, ID.hXOR, ID.pAND, ID.Bpp); + finally + Bitmap.DirectCopy := False; + end; + end; +end; + +procedure TKIcon.CopyToBitmap(Index: Integer; Bitmap: TBitmap); +var + DC: HDC; + ID: TKIconData; + Mask: TBitmap; +begin + if (Index >= 0) and (Index < FIconCount) and (Bitmap <> nil) then + begin + ID := FIconData[Index]; + {$IFDEF FPC} + Bitmap.PixelFormat := PixelFormatFromBpp(ID.Bpp); + {$ELSE} + Bitmap.PixelFormat := pf32bit; + {$ENDIF} + Bitmap.Width := ID.Width; // SetSize not supported prior Delphi 2006 + Bitmap.Height := ID.Height; + if ID.IsPng then + {$IFDEF USE_PNG_SUPPORT} + Bitmap.Canvas.Draw(0, 0, ID.PNG) + {$ENDIF} + else + begin + Mask := TBitmap.Create; + try + Mask.MonoChrome := True; + Mask.Width := ID.Width; + Mask.Height := ID.Height; + DC := CreateCompatibleDC(0); + try + SelectObject(DC, ID.hXOR); + BitBlt(Bitmap.Canvas.Handle, 0, 0, ID.Width, ID.Height, DC, 0, 0, SRCCOPY); + SelectObject(DC, ID.hAND); + BitBlt(Mask.Canvas.Handle, 0, 0, ID.Width, ID.Height, DC, 0, 0, SRCCOPY); + Bitmap.MaskHandle := Mask.ReleaseHandle; + finally + DeleteDC(DC); + end; + finally + Mask.Free; + end; + end; + end; +end; + +{$IFDEF USE_PNG_SUPPORT} +procedure TKIcon.CopyToPng(Index: Integer; Png: TKPngImage); +var + ID: TKIconData; +{$IFNDEF FPC} + I, J: Integer; + C: TKColorRec; + Bitmap: TKAlphaBitmap; +{$ENDIF} +begin + if (Index >= 0) and (Index < FIconCount) and (Png <> nil) then + begin + ID := FIconData[Index]; + if ID.IsPNG then + Png.Assign(ID.PNG) + else + begin + {$IFDEF FPC} + Png.LoadFromBitmapHandles(ID.hXOR, ID.hAND); + {$ELSE} + Bitmap := TKAlphaBitmap.Create; + try + Bitmap.SetSize(ID.Width, ID.Height); + Bitmap.DirectCopy := True; + InternalCopyToAlphaBitmap(Bitmap, ID.hXOR, ID.pAND, ID.Bpp); + Png.CreateBlank(COLOR_RGBALPHA, 8, ID.Width, ID.Height); + for I := 0 to ID.Width - 1 do + for J := 0 to ID.Height - 1 do + begin + C := Bitmap.Pixel[I, J]; + Png.Pixels[I, J] := C.Value; + Png.AlphaScanline[J][I] := C.A; + end; + finally + Bitmap.Free; + end; + {$ENDIF} + end; + end; +end; +{$ENDIF} + +function TKIcon.CreateHandle(Index: Integer): HICON; +var + ABpp, ANDSize, XORSize: Integer; + PID: PKIconData; + PBI: PBitmapInfo; + DC: HDC; + hBmp: HBITMAP; + ANDBits, XORBits: Pointer; +begin + Result := 0; + if FIconData <> nil then + begin + DC := GetDC(0); + try + ABpp := GetDeviceCaps(DC, PLANES) * GetDeviceCaps(DC, BITSPIXEL); + if ABpp <> FBpp then + Update; + if FDisplayAll then + begin + if (Index < 0) or (Index >= FIconCount) then + Index := 0; + end + else if (Index < 0) or (Index >= FIconCount) then + Index := FCurrentIndex; + PID := @FIconData[Index]; + CalcBitmapSizes(PID.Width, PID.Height, FBpp, XORSize, ANDSize); + GetMem(XORBits, XORSize); + try + GetMem(ANDBits, XORSize); + try + PBI := PID.iXOR; + hBmp := GDICheck(CreateDIBitmap(DC, PBI.bmiHeader, CBM_INIT, PID.pXOR, PBI^, DIB_RGB_COLORS)); + try + GetBitmapBits(hBmp, XORSize, XORBits); // obsolete, but the only that works fine... + GetBitmapBits(PID.hAND, ANDSize, ANDbits); + Result := CreateIcon(HInstance, PID.Width, PID.Height, 1, FBpp, ANDBits, XORBits); + finally + if hBmp <> 0 then DeleteObject(hBmp); + end; + finally + FreeMem(ANDBits); + end; + finally + FreeMem(XORBits); + end; + finally + ReleaseDC(0, DC); + end; + end +end; + +procedure TKIcon.Delete(Index: Integer); +var + I: Integer; +begin + if (Index >= 0) and (Index < FIconCount) then + begin + FreeSubimage(@FIconData[Index]); + for I := Index + 1 to FIconCount - 1 do + FIconData[I - 1] := FIconData[I]; + Dec(FIconCount); + SetLength(FIconData, FIconCount); + Changed(Self); + end; +end; + +procedure TKIcon.Draw(ACanvas: TCanvas; const Rect: TRect); + + procedure Display(const P, WH: TPoint; Index: Integer); + var + ID: TKIconData; + Stretch: Boolean; + DC, DC_XOR, DC_AND: HDC; + BM_XOR, BM_AND: HBITMAP; + Obj, Obj_XOR, Obj_AND: HGDIObj; + begin + if (Index >= 0) and (Index < FIconCount) then + begin + ID := FIconData[Index]; + if ID.IsPNG then + begin + {$IFDEF USE_PNG_SUPPORT} + ACanvas.StretchDraw(Classes.Rect(P.X, P.Y, P.X + WH.X, P.Y + WH.Y), ID.PNG); + {$ENDIF} + end else + begin + Stretch := FStretchEnabled and ((WH.X <> ID.Width) or (WH.Y <> ID.Height)); + DC := GDICheck(CreateCompatibleDC(0)); + try + Obj := SelectObject(DC, ID.hXOR); + if Stretch then + begin + DC_XOR := GDICheck(CreateCompatibleDC(DC)); + try + BM_XOR := GDICheck(CreateCompatibleBitmap(DC, WH.X, WH.Y)); + try + DC_AND := GDICheck(CreateCompatibleDC(DC)); + try + BM_AND := GDICheck(CreateMonochromeBitmap(WH.X, WH.Y)); + try + Obj_XOR := SelectObject(DC_XOR, BM_XOR); + Obj_AND := SelectObject(DC_AND, BM_AND); + //SetStretchBltMode(DC_XOR, HALFTONE); //does not distribute alpha channel etc. + StretchBlt(DC_XOR, 0, 0, WH.X, WH.Y, DC, 0, 0, ID.Width, ID.Height, SRCCOPY); + SelectObject(DC, ID.hAND); + StretchBlt(DC_AND, 0, 0, WH.X, WH.Y, DC, 0, 0, ID.Width, ID.Height, SRCCOPY); + MaskOrBitBlt(ACanvas, P.X, P.Y, WH.X, WH.Y, DC_XOR, DC_AND, BM_XOR, BM_AND, + nil, 0, nil, 0, ID.Bpp, FIconDrawStyle); + SelectObject(DC_XOR, Obj_XOR); + SelectObject(DC_AND, Obj_AND); + finally + DeleteObject(BM_AND); + end; + finally + DeleteDC(DC_AND); + end; + finally + DeleteObject(BM_XOR); + end; + finally + DeleteDC(DC_XOR); + end; + end else + MaskOrBitBlt(ACanvas, P.X, P.Y, ID.Width, ID.Height, DC, 0, ID.hXOR, ID.hAND, + ID.pXOR, ID.pXORSize, ID.pAND, ID.pANDSize, ID.Bpp, FIconDrawStyle); + SelectObject(DC, Obj); + finally + DeleteDC(DC); + end; + end; + end; + end; + +var + ABpp, AWidth, AHeight, I: Integer; + P, WH, WH_S: TPoint; +begin + with ACanvas do if FIconData <> nil then + begin + P := Rect.TopLeft; + WH := Point(Rect.Right - Rect.Left, Rect.Bottom - Rect.Top); + if not FStretchEnabled then + begin + Inc(P.X, (WH.X - Width) div 2); + Inc(P.Y, (WH.Y - Height) div 2); + end; + if FDisplayAll then + begin + AWidth := Width; + AHeight := Height; + WH_S := WH; + for I := 0 to FIconCount - 1 do + begin + WH_S.X := FIconData[I].Width * WH.X div AWidth; + WH_S.Y := FIconData[I].Height * WH.Y div AHeight; + Display(P, WH_S, I); + if FDisplayHorz then + Inc(P.X, (FIconData[I].Width + FSpacing) * WH.X div AWidth) + else + Inc(P.Y, (FIconData[I].Height + FSpacing) * WH.Y div AHeight) + end; + end else + begin + ABpp := GetDeviceCaps(Handle, PLANES) * GetDeviceCaps(Handle, BITSPIXEL); + if ABpp <> FBpp then + Update; + Display(P, WH, FCurrentIndex); + end; + end; +end; + +function TKIcon.GetDimensions(Index: Integer): TKIconDimension; +begin + Result.Width := 0; Result.Height := 0; + if (Index >= 0) and (Index < FIconCount) then + begin + Result.Width := FIconData[Index].Width; + Result.Height := FIconData[Index].Height; + end; +end; + +function TKIcon.GetEmpty: Boolean; +begin + Result := FIconData = nil; +end; + +function TKIcon.GetHandles(Index: Integer): TKIconHandles; +begin + if (Index >= 0) and (Index < FIconCount) then + begin + Result.hXOR := FIconData[Index].hXOR; + Result.hAND := FIconData[Index].hAND; + end else + begin + Result.hXOR := 0; + Result.hAND := 0; + end; +end; + +function TKIcon.GetHeight: Integer; +begin + if FDisplayAll and (FIconCount > 0) then + Result := FMaxHeight + else + Result := Heights[FCurrentIndex]; +end; + +function TKIcon.GetTransparent: Boolean; +begin + Result := True; +end; + +function TKIcon.GetHeights(Index: Integer): Integer; +begin + Result := 0; + if (Index >= 0) and (Index < FIconCount) then + Result := FIconData[Index].Height; +end; + +function TKIcon.GetHotSpot(Index: Integer): TPoint; +begin + Result.X := 0; Result.Y := 0; + if (Index >= 0) and (Index < FIconCount) then + Result := FIconData[Index].HotSpot; +end; + +function TKIcon.GetIconData(Index: Integer): TKIconData; +begin + FillChar(Result, SizeOf(TKIconData), #0); + if (Index >= 0) and (Index < FIconCount) then + Result := FIconData[Index]; +end; + +function TKIcon.GetWidth: Integer; +begin + if FDisplayAll and (FIconCount > 0) then + Result := FMaxWidth + else + Result := Widths[FCurrentIndex]; +end; + +function TKIcon.GetWidths(Index: Integer): Integer; +begin + Result := 0; + if (Index >= 0) and (Index < FIconCount) then + Result := FIconData[Index].Width; +end; + +procedure TKIcon.Insert(Index: Integer; const Handles: TKIconHandles); +var + I: Integer; +begin + if Index >= 0 then + if Index < FIconCount then + begin + Inc(FIconCount); + SetLength(FIconData, FIconCount); + for I := FIconCount - 2 downto Index do + FIconData[I + 1] := FIconData[I]; + FillChar(FIconData[Index], SizeOf(TKIconData), 0); + LoadHandles(Index, Handles, True); + end else + Add(Handles); +end; + +{$IFNDEF FPC} +procedure TKIcon.LoadFromClipboardFormat(AFormat: Word; AData: THandle; + APalette: HPALETTE); +begin + // does nothing +end; +{$ENDIF} + +procedure TKIcon.LoadFromHandle(Handle: HICON); +var + Handles: TKIconHandles; + Info: TIconInfo; +begin + if (Handle <> 0) and GetIconInfo(Handle, Info) then + try + Clear; + SetLength(FIconData, 1); + FillChar(FIconData[0], SizeOf(TKIconData), 0); + FIconCount := 1; + Handles.hXOR := Info.hbmColor; + Handles.hAND := Info.hbmMask; + LoadHandles(0, Handles, False); + finally + DeleteObject(Info.hbmColor); + DeleteObject(Info.hbmMask); + end; +end; + +procedure TKIcon.LoadFromAssocFile(const FileName: string); +begin + try + LoadFromAssocExtension(ExtractFileExt(FileName)); + except + LoadFromModuleByIndex(FileName, 0); + end; +end; + +procedure TKIcon.LoadFromAssocExtension(const Extension: string); +const + IconKey = 'DefaultIcon'; +var + Code, DashPos, I: Integer; + Module, S, T: string; + Reg: TRegistry; +begin + if Extension = '' then Error(SIconAssocResolveError); + Reg := TRegistry.Create(KEY_READ); + try + Reg.RootKey := HKEY_CLASSES_ROOT; + if not Reg.KeyExists(Extension) then Error(SIconAssocResolveError); + Reg.OpenKeyReadOnly(Extension); + try + S := Reg.ReadString(''); + finally + Reg.CloseKey; + end; + if S = '' then Error(SIconAssocResolveError); + S := Format('%s\%s', [S, IconKey]); + if not Reg.KeyExists(S) then Error(SIconAssocResolveError); + Reg.OpenKeyReadOnly(S); + try + S := Reg.ReadString(''); + if S = '' then Error(SIconAssocResolveError); + finally + Reg.CloseKey; + end; + finally + Reg.Free; + end; + DashPos := Pos(',', S); + if DashPos > 1 then + Module := Copy(S, 1, DashPos - 1) + else + Module := S; + while CharInSetEx(Module[1], [#9, #32, '''', '"']) do System.Delete(Module, 1, 1); + while CharInSetEx(Module[Length(Module)], [#9, #32, '''', '"']) do System.Delete(Module, Length(Module), 1); + if Module[1] = '%' then + begin + System.Delete(Module, 1, 1); + I := Pos('%', Module); + if I >= 1 then + begin + T := GetEnvironmentVariable(Copy(Module, 1, I - 1)); + if T <> '' then + begin + System.Delete(Module, 1, I); + Module := T + Module; + end; + end; + end; + if not FileExists(Module) then Error(SIconAssocResolveError); + T := LowerCase(ExtractFileExt(Module)); + if T = '.ico' then + LoadFromFile(Module) + else + begin + if DashPos > 0 then + begin + T := Copy(S, DashPos + 1, Length(S)); + while CharInSetEx(T[1], [#9, #32]) do System.Delete(T, 1, 1); + Val(T, I, Code); + end else + begin + I := 0; + Code := 0; + end; + if (Code = 0) and (I >= 0) then + LoadFromModuleByIndex(Module, I) + else + begin + if Code = 0 then + T[1] := '#'; + LoadFromModule(Module, T); + end; + end; +end; + +procedure TKIcon.LoadFromModule(const ModuleName: string; ID: Word); +begin + LoadFromModule(ModuleName, Format('#%d', [ID])); +end; + +procedure TKIcon.LoadFromModule(const ModuleName, ResName: string); +var + Module: HINST; +begin + Module := LoadLibraryEx(PChar(ModuleName), 0, LOAD_LIBRARY_AS_DATAFILE); + if Module = 0 then Error(SIconInvalidModule); + try + LoadFromResource(Module, ResName); + finally + FreeLibrary(Module); + end; +end; + +procedure TKIcon.LoadFromModuleByIndex(const ModuleName: string; Index: Integer); +var + Module: HINST; +begin + Module := LoadLibraryEx(PChar(ModuleName), 0, LOAD_LIBRARY_AS_DATAFILE); + if Module = 0 then Error(SIconInvalidModule); + try + LoadFromResourceByIndex(Module, Index); + finally + FreeLibrary(Module); + end; +end; + +procedure TKIcon.LoadFromResource(Instance: HINST; ID: Word); +begin + LoadFromResource(Instance, Format('#%d', [ID])); +end; + +procedure TKIcon.LoadFromResource(Instance: HINST; const ResName: string); +const + ResGroup: array[Boolean] of PChar = (RT_GROUP_ICON, RT_GROUP_CURSOR); + ResItem: array[Boolean] of PChar = (RT_ICON, RT_CURSOR); +var + I, L, IconName, ANDSize, PalSize, XORInfoSize, XORSize: Integer; + Masked: Boolean; + PIC: PKIconCursorInRes; + PBIn: PBitmapInfo; + PID: PKIcondata; + BIMask: TKMaskBitmapInfo; + hGroup, hItem: HRSRC; + hMemGroup, hMem: HGLOBAL; + DC: HDC; + HSign: TKImageHeaderString; +{$IFDEF USE_PNG_SUPPORT} + Stream: TMemoryStream; +{$ENDIF} + + function GetResSize(Instance: HINST; Entry : PKIconCursorDirEntryInRes) : integer; + var + Rsrc: HRSRC; + C: Cardinal; + begin + Result := Entry.dwBytesInRes; + Rsrc := FindResource(Instance, Pointer(Entry.wEntryName), RT_ICON); + if Rsrc <> 0 then + begin + C := SizeofResource(Instance,Rsrc); + if C <> 0 then // maybe if C > Result ?? + Result := C; + end; + end; + +begin + hGroup := FindResource(Instance, PChar(ResName), ResGroup[FCursor]); + if hGroup = 0 then Error(SIconResourceError); + hMemGroup := LoadResource(Instance, hGroup); + if hMemGroup = 0 then Error(SIconResourceError); + PIC := LockResource(hMemGroup); + if (PIC.IH.idType = 1) and FCursor or (PIC.IH.idType = 2) and not FCursor then + Error(SIconResourceError); + DC := GetDC(0); + try + Clear; + FIconCount := PIC.IH.idCount; + SetLength(FIconData, FIconCount); + FillChar(FIconData[0], SizeOf(TKIconData) * FIconCount, 0); + for I := 0 to PIC.IH.idCount - 1 do + begin + IconName := PIC.Entries[I].wEntryName; + hItem := FindResource(Instance, PChar(IconName), ResItem[FCursor]); + if hItem = 0 then Error(SIconResourceError); + hMem := LoadResource(Instance, hItem); + if hMem = 0 then Error(SIconResourceError); + PBIn := LockResource(hMem); + try + PID := @FIconData[I]; + try + if FCursor then + begin + PID.Width := PIC.Entries[I].Info.Cursor.Width; + PID.Height := PIC.Entries[I].Info.Cursor.Height; + PID.HotSpot.X := PKCursorHotSpot(PBIn).xHotSpot; + PID.HotSpot.Y := PKCursorHotSpot(PBIn).yHotSpot; + Inc(Integer(PBIn), SizeOf(TKCursorHotSpot)); + end else + begin + PID.Width := PIC.Entries[I].Info.Icon.Width; + PID.Height := PIC.Entries[I].Info.Icon.Height; + end; + if PID.Width = 0 then PID.Width := 256; + if PID.Height = 0 then PID.Height := 256; +// PID.BytesInRes := PIC.Entries[I].dwBytesInRes; // gigo + PID.BytesInRes := GetResSize(Instance,@PIC.Entries[I]); + PID.Bpp := PIC.Entries[I].wBitCount; + L := Min(8, PID.BytesInRes); + Byte(HSign[0]) := L; + Move(PBIn^, HSign[1], L); + if (HSign = PNGHeader) or (HSign = MNGHeader) then + begin + PID.IsPNG := True; + PID.PNG := TKIconPngObject.Create; + {$IFDEF USE_PNG_SUPPORT} + Stream := TMemoryStream.Create; + try + Stream.Write(PBIn^, PID.BytesInRes); + Stream.Seek(0, soFromBeginning); + PID.PNG.LoadFromStream(Stream); + finally + Stream.Free; + end; + {$ELSE} + PID.PNG.Write(PBIn^, PID.BytesInRes); + {$ENDIF} + end else + begin + //PID.Bpp := PIC.Entries[I].wBitCount; // this is wrong in some icons + PID.Bpp := PBIn.bmiHeader.biBitCount; + PID.Width := PBIn.bmiHeader.biWidth; // gigo + PID.Height := PBIn.bmiHeader.biHeight shr 1; // gigo + CalcBitmapSizes(PID.Width, PID.Height, PID.Bpp, XORSize, ANDSize); + PalSize := GetPaletteSize(PID.Bpp); + XORInfoSize := SizeOf(TBitmapInfoHeader) + PalSize * SizeOf(TRGBQuad); + Masked := PID.BytesInRes = XORInfoSize + XORSize + ANDSize; + if not Masked then Error(SIconFormatError); + GetMem(PID.iXOR, XORInfoSize); + PID.iXORSize := XORInfoSize; + Move(PBIn^, PID.iXOR^, XORInfoSize); + PID.iXOR.bmiHeader.biHeight := PID.iXOR.bmiHeader.biHeight div 2; + PID.hXOR := GDICheck(CreateDIBSection(DC, PID.iXOR^, + DIB_RGB_COLORS, PID.pXOR, 0, 0)); + if PID.pXOR <> nil then + begin + Move(Pointer(Cardinal(PBIn) + Cardinal(XORInfoSize))^, PID.pXOR^, XORSize); + PID.pXORSize := XORSize; + end else + Error(SIconAllocationError); + CreateMaskInfo(PID.Width, PID.Height, BIMask); + PID.hAND := GDICheck(CreateDIBSection(DC, PBitmapInfo(@BIMask)^, + DIB_RGB_COLORS, PID.pAND, 0, 0)); + if PID.pAND <> nil then + begin + Move(Pointer(Cardinal(PBIn) + Cardinal(XORInfoSize + XORSize))^, PID.pAND^, ANDSize); + PID.pANDSize := ANDSize; + end else + Error(SIconAllocationError); + end; + except + FreeSubimage(PID); + raise; + end; + finally + UnlockResource(hMem); // this is not necessary, but... + FreeResource(hMem); + end; + end; + finally + ReleaseDC(0, DC); + UnlockResource(hMemGroup); // this is not necessary, but... + FreeResource(hMemGroup); + end; + Changed(Self); +end; + +type + PCallBack = ^TCallBack; + TCallBack = record + I, + Index: Integer; + S: string; + end; + + function EnumIcons(hModule: HINST; lpType: DWORD; lpName: PChar; dwParam: DWORD): BOOL; stdcall; + var + CB: PCallBack; + begin + CB := PCallBack(dwParam); + if CB.I = CB.Index then + begin + if HiWord(Cardinal(lpName)) = 0 then + CB.S := Format('#%d', [Cardinal(lpName)]) + else + CB.S := lpName; + Result := False; + end else + Result := True; + Inc(CB.I); + end; + +procedure TKIcon.LoadFromResourceByIndex(Instance: HINST; Index: Integer); +var + CB: TCallBack; +begin + CB.I := 0; + CB.Index := Index; + CB.S := ''; + EnumResourceNames(Instance, RT_GROUP_ICON, @EnumIcons, DWORD(@CB)); + if CB.S <> '' then + LoadFromResource(Instance, CB.S) + else if CB.I = 0 then + Error(SIconInvalidModule) + else + Error(SIconIndexError); +end; + +procedure TKIcon.LoadFromStream(Stream: TStream); +var + I, ANDSize, PalSize, XORInfoSize, XORSize: Integer; + Masked: Boolean; + PID: PKIconData; + IH: TKIconHeader; + II: TKIconCursorDirEntry; + BI: TBitmapInfoHeader; + BIMask: TKMaskBitmapInfo; + DC: HDC; + HSign: TKImageHeaderString; +{$IFDEF USE_PNG_SUPPORT} + MS: TMemoryStream; +{$ENDIF} +begin + if Stream <> nil then + begin + DC := GetDC(0); + try + Clear; + Stream.Read(IH, SizeOf(TKIconHeader)); + FCursor := IH.idType = 2; + FIconCount := IH.idCount; + SetLength(FIconData, FIconCount); + FillChar(FIconData[0], SizeOf(TKIconData) * FIconCount, 0); + for I := 0 to FIconCount - 1 do + begin + PID := @FIconData[I]; + Stream.Read(II, SizeOf(TKIconCursorDirEntry)); + // for PNG read icon size here, otherwise this is overwritten when XOR bitmap is read + PID.Width := II.Width; + if PID.Width = 0 then PID.Width := 256; + PID.Height := II.Height; + if PID.Height = 0 then PID.Height := 256; + if FCursor then + begin + PID.HotSpot.X := II.Info.wX; + PID.HotSpot.Y := II.Info.wY; + end; + PID.BytesInRes := II.dwBytesInRes; + PID.Offset := II.dwImageOffset; + PID.Bpp := II.Info.wBitCount; // for PNG icons bpp is stored here + end; + for I := 0 to FIconCount - 1 do + begin + PID := @FIconData[I]; + try + Byte(HSign[0]) := Stream.Read(HSign[1], 8); + Stream.Seek(-8, soFromCurrent); + if (HSign = PNGHeader) or (HSign = MNGHeader) then + begin + PID.IsPNG := True; + PID.PNG := TKIconPngObject.Create; + {$IFDEF USE_PNG_SUPPORT} + MS := TMemoryStream.Create; + try + MS.CopyFrom(Stream, PID.BytesInRes); // secure icon integrity + MS.Seek(0, soFromBeginning); + PID.PNG.LoadFromStream(MS); + finally + MS.Free; + end; + {$ELSE} + PID.PNG.CopyFrom(Stream, PID.BytesInRes); + {$ENDIF} + end else + begin + Stream.Read(BI, SizeOf(TBitmapInfoHeader)); + PID.Bpp := BI.biBitCount; + PID.Width := BI.biWidth; + PID.Height := BI.biHeight shr 1; + PalSize := GetPaletteSize(PID.Bpp); + CalcBitmapSizes(PID.Width, PID.Height, PID.Bpp, XORSize, ANDSize); + XORInfoSize := SizeOf(TBitmapInfoHeader) + PalSize * SizeOf(TRGBQuad); + Masked := PID.BytesInRes = XORInfoSize + XORSize + ANDSize; + if not Masked then Error(SIconFormatError); + BI.biHeight := BI.biHeight div 2; + GetMem(PID.iXOR, XORInfoSize); + PID.iXORSize := XORInfoSize; + PID.iXOR.bmiHeader := BI; + PID.iXOR.bmiHeader.biSizeImage := 0; + Stream.Read(PID.iXOR.bmiColors, PalSize * SizeOf(TRGBQuad)); + PID.hXOR := GDICheck(CreateDIBSection(DC, PID.iXOR^, + DIB_RGB_COLORS, PID.pXOR, 0, 0)); + if PID.pXOR <> nil then + begin + Stream.Read(PID.pXOR^, XORSize); + PID.pXORSize := XORSize; + end else + Error(SIconAllocationError); + CreateMaskInfo(PID.Width, PID.Height, BIMask); + PID.hAND := GDICheck(CreateDIBSection(DC, PBitmapInfo(@BIMask)^, + DIB_RGB_COLORS, PID.pAND, 0, 0)); + if PID.pAND <> nil then + begin + Stream.Read(PID.pAND^, ANDSize); + PID.pANDSize := ANDSize; + end else + Error(SIconAllocationError); + end; + except + FreeSubimage(PID); + raise; + end; + end; + finally + ReleaseDC(0, DC); + end; + Changed(Self); + end; +end; + +procedure TKIcon.LoadHandles(Index: Integer; const Handles: TKIconHandles; OrigBpp: Boolean); +var + ANDSize, PalSize, XORSize, XORInfoSize: Integer; + PID: PKIconData; + BInfo: Windows.TBitmap; + BIMask: TKMaskBitmapInfo; + P: Pointer; + DC: HDC; + hBmp: HBITMAP; +begin + if (Index >= 0) and (Index < FIconCount) then + begin + PID := @FIconData[Index]; + if (Handles.hAND = 0) or + (Handles.hXOR = PID.hXOR) or (Handles.hAND = PID.hXOR) or + (Handles.hXOR = PID.hAND) or (Handles.hAND = PID.hAND) then + Error(SIconBitmapError); + FreeSubimage(PID); + DC := GetDC(0); + try + try + if Handles.hXOR <> 0 then + begin + GetObject(Handles.hXOR, SizeOf(Windows.TBitmap), @BInfo); + PID.Height := BInfo.bmHeight; + if OrigBpp or (FInHandleBpp = 0) then + PID.Bpp := BInfo.bmPlanes * BInfo.bmBitsPixel + else + PID.Bpp := FInHandleBpp; + end else + begin // must be a monochrome icon - not fully tested + GetObject(Handles.hAND, SizeOf(Windows.TBitmap), @BInfo); + PID.Height := BInfo.bmHeight div 2; + PID.Bpp := 1; + end; + PID.Width := BInfo.bmWidth; + CalcBitmapSizes(PID.Width, PID.Height, PID.Bpp, XORSize, ANDSize); + PalSize := GetPaletteSize(PID.Bpp); + XORInfoSize := SizeOf(TBitmapInfoHeader) + PalSize * SizeOf(TRGBQuad); + GetMem(PID.iXOR, XORInfoSize); + PID.iXORSize := XORInfoSize; + FillChar(PID.iXOR^, XORInfoSize, 0); + PID.BytesInRes := XORInfoSize; + PID.iXOR.bmiHeader.biSize := SizeOf(TBitmapInfoHeader); + PID.iXOR.bmiHeader.biWidth := PID.Width; + PID.iXOR.bmiHeader.biHeight := PID.Height; + PID.iXOR.bmiHeader.biPlanes := 1; + PID.iXOR.bmiHeader.biBitCount := PID.Bpp; + PID.iXOR.bmiHeader.biCompression := BI_RGB; + if Handles.hXOR <> 0 then hBmp := Handles.hXOR else hBmp := Handles.hAND; + GetDIBits(DC, hBmp, 0, PID.Height, nil, PID.iXOR^, DIB_RGB_COLORS); + PID.hXOR := GDICheck(CreateDIBSection(DC, PID.iXOR^, + DIB_RGB_COLORS, PID.pXOR, 0, 0)); + if PID.pXOR <> nil then + begin + GetDIBits(DC, hBmp, 0, PID.Height, PID.pXOR, + PID.iXOR^, DIB_RGB_COLORS); + PID.pXORSize := XORSize; + if (PID.Bpp = 32) and FInHandleFullAlpha then + FillAlphaIfNone(PKColorRecs(PID.pXOR), XORSize, $FF); + Inc(PID.BytesInRes, XORSize); + end else + Error(SIconAllocationError); + CreateMaskInfo(PID.Width, PID.Height, BIMask); + PID.hAND := GDICheck(CreateDIBSection(DC, PBitmapInfo(@BIMask)^, + DIB_RGB_COLORS, PID.pAND, 0, 0)); + if PID.pAND <> nil then + begin + if Handles.hXOR <> 0 then + begin + GetDIBits(DC, Handles.hAND, 0, PID.Height, PID.pAND, + PBitmapInfo(@BIMask)^, DIB_RGB_COLORS); + end else + begin + GetMem(P, ANDSize * 2); + try + BIMask.Header.biHeight := 2 * PID.Height; + GetDIBits(DC, Handles.hAND, 0, PID.Height * 2, P, + PBitmapInfo(@BIMask)^, DIB_RGB_COLORS); + Move(P^, PID.pAND^, ANDSize); + finally + FreeMem(P); + end; + end; + PID.pANDSize := ANDSize; + Inc(PID.BytesInRes, ANDSize); + end else + Error(SIconAllocationError); + except + FreeSubimage(PID); + raise; + end; + finally + ReleaseDC(0, DC); + end; + Changed(Self); + end; +end; + +procedure TKIcon.MaskFromColor(Index: Integer; Color: TColor; HasAlpha: Boolean = False); +var + PID: PKIconData; + DC: HDC; + OldObj: HGDIObj; + BM: TKAlphaBitmap; + ByteMask: Byte; + I, J, L, LAnd: Integer; + ColorMask: Cardinal; + P: PKColorRecs; + Q: PBytes; +begin + if (Index >= 0) and (Index < FIconCount) then + begin + Color := SwitchRGBToBGR(Color); + PID := @FIconData[Index]; + DC := 0; + BM := TKAlphaBitmap.Create; + try + BM.SetSize(PID.Width, PID.Height); + DC := GDICheck(CreateCompatibleDC(0)); + OldObj := SelectObject(DC, PID.hXOR); + BitBlt(BM.Canvas.Handle, 0, 0, PID.Width, PID.Height, DC, 0, 0, SRCCOPY); + FillChar(PID.pAND^, PID.pANDSize, $FF); + LAnd := CalcByteWidth(PID.Width, 1); + Q := PID.pAND; + Inc(Cardinal(Q), PID.pANDSize - LAnd); + if HasAlpha then ColorMask := $FFFFFFFF else ColorMask := $00FFFFFF; + for I := 0 to PID.Height - 1 do + begin + ByteMask := $7F; + P := BM.ScanLine[I]; + for J := 0 to PID.Width - 1 do + begin + L := J shr 3; + if P[J].Value and ColorMask <> Cardinal(Color) then + Q[L] := Q[L] and ByteMask; + asm + ror ByteMask, 1 + end; + end; + Dec(Cardinal(Q), LAnd); + end; + SelectObject(DC, OldObj); + finally + if DC <> 0 then DeleteDC(DC); + BM.Free; + end; + Changed(Self); + end; +end; + +procedure TKIcon.SaveToStream(Stream: TStream); +var + I, Offset, RSize: Integer; + IH: TKIconHeader; + PID: PKIconData; + II: TKIconCursorDirEntry; +{$IFDEF USE_PNG_SUPPORT} + J, Delta: Integer; + MS: TMemoryStream; +{$ENDIF} +begin + if (Stream <> nil) and (FIconData <> nil) then + begin + Offset := SizeOf(TKIconHeader) + FIconCount * SizeOf(TKIconCursorDirEntry); + IH.idReserved := 0; + if FCursor then IH.idType := 2 else IH.idType := 1; + IH.idCount := 0; + for I := 0 to FIconCount - 1 do + if (FIconData[I].iXOR <> nil) or FIconData[I].IsPNG then + Inc(IH.idCount); + Stream.Write(IH, SizeOf(TKIconHeader)); + for I := 0 to FIconCount - 1 do + begin + FillChar(II, SizeOf(TKIconCursorDirEntry), 0); // gigo + PID := @FIconData[I]; + if PID.IsPNG then + begin + II.Width := PID.Width; + II.Height := PID.Height; + II.ColorCount := GetPaletteSize(PID.Bpp); + II.Info.wPlanes := 1; + II.Info.wBitCount := PID.Bpp; + II.dwBytesInRes := PID.BytesInRes; + II.dwImageOffset := Offset; + Stream.Write(II, SizeOf(TKIconCursorDirEntry)); + Inc(Offset, PID.BytesInRes); + end + else if PID.iXOR <> nil then + begin + II.Width := PID.Width; + II.Height := PID.Height; + II.ColorCount := GetPaletteSize(PID.Bpp); + if FCursor then + begin + II.Info.wX := PID.HotSpot.X; + II.Info.wY := PID.HotSpot.Y; + end else + begin + II.Info.wPlanes := 1; + II.Info.wBitCount := PID.Bpp; + end; + RSize := PID.iXORSize + PID.pXORSize + PID.pANDSize; + II.dwBytesInRes := RSize; + II.dwImageOffset := Offset; + Stream.Write(II, SizeOf(TKIconCursorDirEntry)); + Inc(Offset, RSize); + end; + end; + for I := 0 to FIconCount - 1 do + begin + PID := @FIconData[I]; + if PID.IsPNG then + begin + {$IFDEF USE_PNG_SUPPORT} + MS := TMemoryStream.Create; + try + PID.PNG.SaveToStream(MS); + MS.Seek(0, soFromBeginning); + //// gigo + if Ms.Size <> PID.BytesInRes then + begin + Delta := PID.BytesInRes - MS.Size; + PID.BytesInRes := MS.Size; + Stream.Seek(SizeOf(TKIconHeader) + I * SizeOf(TKIconCursorDirEntry), soFromBeginning); + Stream.Read(II, SizeOf(TKIconCursorDirEntry)); + II.dwBytesInRes := PID.BytesInRes; + Stream.Seek(-1 * SizeOf(TKIconCursorDirEntry), soFromCurrent); + Stream.Write(II, SizeOf(TKIconCursorDirEntry)); + for J := I + 1 to FIconCount - 1 do + begin + Stream.Read(II, SizeOf(TKIconCursorDirEntry)); + II.dwImageOffset := II.dwImageOffset - Delta; + Stream.Seek(-1 * SizeOf(TKIconCursorDirEntry), soFromCurrent); + Stream.Write(II, SizeOf(TKIconCursorDirEntry)); + end; + Stream.Seek(0,soFromEnd); + end; + //// end gigo + Stream.CopyFrom(MS, PID.BytesInRes); // secure icon integrity + finally + MS.Free; + end; + {$ELSE} + PID.PNG.Seek(0, soFromBeginning); + Stream.CopyFrom(PID.PNG, PID.BytesInRes); + {$ENDIF} + end else if PID.iXOR <> nil then + begin + PID.iXOR.bmiHeader.biHeight := PID.iXOR.bmiHeader.biHeight * 2; + Stream.Write(PID.iXOR^, PID.iXORSize); + PID.iXOR.bmiHeader.biHeight := PID.iXOR.bmiHeader.biHeight div 2; + Stream.Write(PID.pXOR^, PID.pXORSize); + Stream.Write(PID.pAND^, PID.pANDSize); + end; + end; + end; +end; + +{$IFNDEF FPC} +procedure TKIcon.SaveToClipboardFormat(var Format: Word; var Data: THandle; + var APalette: HPALETTE); +begin + // does nothing +end; +{$ENDIF} + +procedure TKIcon.SetCurrentIndex(Value: Integer); +begin + if (Value >= 0) and (Value < FIconCount) and (Value <> FCurrentIndex) then + begin + FCurrentIndex := Value; + Changed(Self); + end; +end; + +procedure TKIcon.SetDisplayAll(Value: Boolean); +begin + if Value <> FDisplayAll then + begin + FDisplayAll := Value; + Changed(Self); + end; +end; + +procedure TKIcon.SetDisplayHorz(Value: Boolean); +begin + if Value <> FDisplayHorz then + begin + FDisplayHorz := Value; + Changed(Self); + end; +end; + +procedure TKIcon.SetDimensions(Index: Integer; Value: TKIconDimension); +begin + if (Index >= 0) and (Index < FIconCount) and + (Value.Width > 0) and (Value.Height > 0) and + (Value.Width <> Widths[Index]) and (Value.Width <> Heights[Index]) then + begin + UpdateDim(Index, Value); + Changed(Self); + end; +end; + +procedure TKIcon.SetHandles(Index: Integer; Value: TKIconHandles); +begin + LoadHandles(Index, Value, True); +end; + +procedure TKIcon.SetHeight(Value: Integer); +begin + if not FDisplayAll then + Heights[FCurrentIndex] := Value; +end; + +procedure TKIcon.SetHeights(Index: Integer; Value: Integer); +var + D: TKIconDimension; +begin + D.Width := Widths[Index]; + D.Height := Value; + Dimensions[Index] := D; +end; + +procedure TKIcon.SetHotSpot(Index: Integer; Value: TPoint); +var + PID: PKIconData; +begin + if (Index >= 0) and (Index < FIconCount) then + begin + PID := @FIconData[Index]; + if (PID.HotSpot.X <> Value.X) or (PID.HotSpot.Y <> Value.Y) then + begin + PID.HotSpot := Value; + Changed(Self); + end; + end; +end; + +procedure TKIcon.SetIconDrawStyle(Value: TKIconDrawStyle); +begin + if Value <> FIconDrawStyle then + begin + FIconDrawStyle := Value; + Changed(Self); + end; +end; + +procedure TKIcon.SetInHandleBpp(Value: Integer); +begin + if Value in [0, 1, 4, 8, 32] then + FInHandleBpp := Value; +end; + +procedure TKIcon.SetOptimalIcon(Value: Boolean); +begin + if Value <> FOptimalIcon then + begin + FOptimalIcon := Value; + Changed(Self); + end; +end; + +procedure TKIcon.SetOverSizeWeight(Value: Single); +begin + if Value <> FOverSizeWeight then + begin + FOverSizeWeight := Value; + Changed(Self); + end; +end; + +procedure TKIcon.SetRequestedSize(Value: TKIconDimension); +begin + if (Value.Width > 0) and (Value.Height > 0) then + begin + FRequestedSize := Value; + Changed(Self); + end; +end; + +procedure TKIcon.SetSpacing(Value: Integer); +begin + if Value <> FSpacing then + begin + FSpacing := Value; + Changed(Self); + end; +end; + +procedure TKIcon.SetStretchEnabled(Value: Boolean); +begin + if Value <> FStretchEnabled then + begin + FStretchEnabled := Value; + Changed(Self); + end; +end; + +procedure TKIcon.SetTransparent(Value: Boolean); +begin + if FCreating then + inherited + else + // Ignore assignments to this property. + // Icons are always transparent. +end; + +procedure TKIcon.SetWidth(Value: Integer); +begin + if not FDisplayAll then + Widths[FCurrentIndex] := Value; +end; + +procedure TKIcon.SetWidths(Index: Integer; Value: Integer); +var + D: TKIconDimension; +begin + D.Width := Value; + D.Height := Heights[Index]; + Dimensions[Index] := D; +end; + +procedure TKIcon.Update; +var + dW, dH, BestBpp, I, MaxWeight, Weight: Integer; + DC: HDC; + PID: PKIconData; +begin + FBpp := 0; + FMaxWidth := 0; + FMaxHeight := 0; + if FIconData <> nil then + begin + DC := GetDC(0); + try + FBpp := GetDeviceCaps(DC, PLANES) * GetDeviceCaps(DC, BITSPIXEL); + MaxWeight := MaxInt; + for I := 0 to FIconCount - 1 do + begin + PID := @FIconData[I]; + if FDisplayAll and FDisplayHorz then + begin + Inc(FMaxWidth, PID.Width); + if I <> 0 then Inc(FMaxWidth, FSpacing); + end else + if PID.Width > FMaxWidth then FMaxWidth := PID.Width; + if FDisplayAll and not FDisplayHorz then + begin + Inc(FMaxHeight, PID.Height); + if I <> 0 then Inc(FMaxHeight, FSpacing); + end else + if PID.Height > FMaxHeight then FMaxHeight := PID.Height; + end; + if FOptimalIcon and (FIconCount >= 2) then + begin + FCurrentIndex := 0; + BestBpp := FIconData[0].Bpp; + for I := 0 to FIconCount - 1 do + begin + PID := @FIconData[I]; + if (PID.Bpp <= FBpp) and (PID.Bpp >= BestBpp) then + begin + BestBpp := PID.Bpp; + dW := FRequestedSize.Width - PID.Width; + dH := FRequestedSize.Height - PID.Height; + if dW < 0 then DW := Round(-DW * FOverSizeWeight); + if dH < 0 then dH := Round(-DH * FOverSizeWeight); + Weight := dW + dH; + if Weight <= MaxWeight then + begin + MaxWeight := Weight; + FCurrentIndex := I; + end; + end; + end; + end + else if (FCurrentIndex < 0) or (FCurrentIndex >= FIconCount) then + FCurrentIndex := 0; + finally + ReleaseDC(0, DC); + end; + end else + FCurrentIndex := -1; +end; + +procedure TKIcon.UpdateDim(Index: Integer; Value: TKIconDimension); + + procedure BitMove(const Src, Dest; BitSize, BitOffset: Integer); + asm + // eax: Src + // ecx: BitSize + // edx: Dest + // stack: BitOffset + // push registers that must be preserved + push esi + push edi + push ebx + // set registers for register adressing + mov esi, eax + mov edi, edx + // test for scroll direction + mov edx, BitOffset + cmp edx, 0 + js @left + // perform move + mov ebx, edx + shr ebx, 3 + add edi, ebx + and edx, $07 + jnz @bitwise_right + // bytewise move + mov edx, ecx + shr ecx, 3 + rep movsb + and dl, $07 + jz @exit + mov cl, dl + mov al, [esi] + rol eax, cl + mov al, [edi] + ror eax, cl + mov [edi], al + jmp @exit + @bitwise_right: + // bitwise move + mov ebx, ecx + mov cl, dl + xor ch, ch + mov dl, $7F + ror dl, cl + mov dh, dl + not dh + @R00: + mov ah, [esi] + ror ah, cl + and ah, dh + mov al, [edi] + and al, dl + or al, ah + mov [edi], al + dec ebx + jz @exit + inc ch + and ch, $07 + jnz @R01 + inc esi + @R01: + ror dl, 1 + ror dh, 1 + test dh, $80 + jz @R00 + inc edi + jmp @R00 + @left: + // perform scroll + neg edx + mov ebx, edx + shr ebx, 3 + add esi, ebx + and edx, $07 + jnz @bitwise_left + // bytewise move + mov edx, ecx + shr ecx, 3 + rep movsb + and dl, $07 + jz @exit + mov cl, dl + mov al, [esi] + rol eax, cl + mov al, [edi] + ror eax, cl + mov [edi], al + jmp @exit + @bitwise_left: + // bitwise move + mov ebx, ecx + mov cl, dl + mov ch, cl + mov dl, $7F + mov dh, dl + not dh + @L00: + mov ah, [esi] + rol ah, cl + and ah, dh + mov al, [edi] + and al, dl + or al, ah + mov [edi], al + dec ebx + jz @exit + inc ch + and ch, $07 + jnz @L01 + inc esi + @L01: + ror dl, 1 + ror dh, 1 + test dh, $80 + jz @L00 + inc edi + jmp @L00 + @exit: + // pop the preserved registers + pop ebx + pop edi + pop esi + end; + +var + BitOffset, J, Size, XOR1, XOR2, AND1, AND2, + X, Y, HOffset, VOffset: Integer; + PID: PKIconData; + PBI: PBitmapInfoHeader; + BIMask: TKMaskBitmapInfo; + P: PByteArray; + hBmp: HBITMAP; + DC: HDC; +begin + PID := @FIconData[Index]; + if PID.iXOR <> nil then + begin + PBI := PBitmapInfoHeader(PID.iXOR); + P := nil; + DC := GetDC(0); + try + try + CalcByteWidths(PID.Width, PID.Bpp, XOR1, AND1); + CalcByteWidths(Value.Width, PID.Bpp, XOR2, AND2); + PBI.biWidth := Value.Width; + PBI.biHeight := Value.Height; + PBI.biSizeImage := XOR2 * Value.Height; + if FAlignStyle = asCenter then + begin + HOffset := (Value.Width - PID.Width) div 2; + VOffset := (Value.Height - PID.Height) div 2; + end else + begin + HOffset := 0; + VOffset := 0; + end; + Y := Min(PID.Height, Value.Height); + BitOffset := HOffset * PID.Bpp; + hBmp := GDICheck(CreateDIBSection(DC, PBitmapInfo(PBI)^, DIB_RGB_COLORS, Pointer(P), 0, 0)); + if P = nil then Error(SIconAllocationError); + X := Min(PID.Width, Value.Width) * PID.Bpp; + Size := XOR2 * Value.Height; + FillChar(P^, Size, #0); + for J := 1 to Y do + begin + if VOffset >= 0 then + BitMove(PByteArray(PID.pXOR)[(PID.Height - J) * XOR1], + P[(Value.Height - J - VOffset) * XOR2], X, BitOffset) + else + BitMove(PByteArray(PID.pXOR)[(PID.Height - J + VOffset) * XOR1], + P[(Value.Height - J) * XOR2], X, BitOffset); + end; + DeleteObject(PID.hXOR); + PID.pXOR := P; + PID.pXORSize := Size; + PID.hXOR := hBmp; + CreateMaskInfo(PID.Width, PID.Height, BIMask); + hBmp := GDICheck(CreateDIBSection(DC, PBitmapInfo(@BIMask)^, DIB_RGB_COLORS, Pointer(P), 0, 0)); + if P = nil then Error(SIconAllocationError); + X := Min(PID.Width, Value.Width); + Size := AND2 * Value.Height; + FillChar(P^, Size, #$FF); + for J := 1 to Y do + begin + if VOffset >= 0 then + BitMove(PByteArray(PID.pAND)[(PID.Height - J) * AND1], + P[(Value.Height - J - VOffset) * AND2], X, HOffset) + else + BitMove(PByteArray(PID.pAND)[(PID.Height - J + VOffset) * AND1], + P[(Value.Height - J) * AND2], X, HOffset); + end; + DeleteObject(PID.hAND); + PID.pAND := P; + PID.pANDSize := Size; + PID.hAND := hBmp; + PID.Width := Value.Width; + PID.Height := Value.Height; + except + FreeSubimage(PID); + Error(SIconResizingError); + end; + finally + ReleaseDC(0, DC); + end; + end; +end; + +procedure RegisterKIcon; +begin + TPicture.UnregisterGraphicClass(Graphics.TIcon); + TPicture.RegisterFileFormat('ico', SVIcons, KIcon.TIcon); + TPicture.RegisterFileFormat('cur', SVCursors, KIcon.TIcon); +end; + +procedure UnregisterKIcon; +begin + TPicture.UnregisterGraphicClass(KIcon.TIcon); + TPicture.RegisterFileFormat('ico', SVIcons, Graphics.TIcon); +end; + +{$IFDEF TKICON_REGISTER} +initialization + RegisterKIcon; +finalization + //not necessary, but... + UnregisterKIcon; +{$ENDIF} + +{$ENDIF} +end. diff --git a/components/kcontrols/source/kprintpreview.dfm b/components/kcontrols/source/kprintpreview.dfm new file mode 100755 index 000000000..a6222c843 --- /dev/null +++ b/components/kcontrols/source/kprintpreview.dfm @@ -0,0 +1,1475 @@ +object KPrintPreviewForm: TKPrintPreviewForm + Left = 324 + Top = 212 + Caption = 'Print Preview' + ClientHeight = 614 + ClientWidth = 812 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + Icon.Data = { + 0000010001001010000001001800680300001600000028000000100000002000 + 00000100180000000000000000000000000000000000000000000000000092B1 + B7373D3C3A424352626552606252606252606252606252606252606252606252 + 606252626590AEB4000000000000393F3F95887B8F8378B9B0A8F1F0EEF1F0EE + F1F0EEF1F0EEF1F0EEF1F0EEF1F0EEF1F0EEEAE8E6585A5AA3C5CC0000003F49 + 49867B70D2CCC6B7ADA3C1BCB6E3E3E3E0E0E0DFDFDFFEFEFEFFFFFFFFFFFFFF + FFFFFFFFFFA5A3A187A4AA000000A5C8CE3C4444A59C93E1DDD9B6ACA2BAB4AF + A69E97A2978CA1968BA9A29BD1D0CEF1F1F1FEFEFEA8A7A587A3A90000000000 + 0087A3A98B8580BAB0A6D4CEC79A8D7EAA9E89C8C0B0CCC3B3BCAE95978B7CE2 + DEDBFDFDFDA9A8A787A3A900000000000087A3A9AAA9A8E0DCD8A29586A9986C + C6BA91D0C7A9D1C9AAC5B990AA986CA4998CF7F6F5AAA9A887A3A90000000000 + 0087A3A9ABAAA9D6D1CCA0906EAD9C60B9AC78BFB485BBB082BAAE79AB9A5EA9 + 9874D9D4D0ABAAA987A3A900000000000087A3A9ACABA9D1CBC4A18D5AB7A45C + B8A866B8A869B9A969BBA963B6A154A7925DD4CEC8ABA9A887A3A90000000000 + 0087A3A9ACABAADAD5D0AB9A6EC7B778CABB80CBBD85C9BA7FC4B371B4A157A8 + 9462DBD5D1A7A5A387A3A900000000000087A3A9ADACABEBE9E6B4A892C5B990 + D7CDA8D9D0AAD8CFAAD8CEA8C2B58CBAAF9AE4E0DC9C989487A3A90000000000 + 0087A3A9ADACABF1EFEDCFCBC8B9AC91D3C8A7F2EEE1F2EEE0D2C6A4BAAD93C9 + C4BFD5CEC781797187A3A900000000000087A3A9ADADACEDEBE9B9B7B5C3C1BE + B8B1A8A59B86A89D87CCC5BBDFD9D4E5E1DDE4E0DC58585599B9BF0000000000 + 0087A3A9AEADACEAE7E4979694B6B4B1ACAAA7A8A6A4A2A09EDAD5CFE8E5E2E6 + E3E06A6D6C8AA7AD00000000000000000087A4AAADACABE6E3DFE6E3DFE6E3DF + E6E3DFE4E1DDDED9D4D3CCC4EBE9E76A6C6D8CAAAF0000000000000000000000 + 00A3C5CC626565EFEEECF0EEECF0EEEBEEEBE9E7E3DFD4CDC6BDB3A86A6C6D8B + A9AF00000000000000000000000000000000000090AEB4536366536164536164 + 536164526063505E614C5A5C8CAAAF0000000000000000000000000000000003 + 0000000100000001000000010000800100008001000080010000800100008001 + 00008001000080010000800100008003000080070000800F0000C01F0000} + KeyPreview = True + OldCreateOrder = False + Position = poScreenCenter + OnCreate = FormCreate + OnKeyDown = FormKeyDown + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object ToBMain: TToolBar + Left = 0 + Top = 0 + Width = 812 + Height = 30 + AutoSize = True + ButtonHeight = 30 + ButtonWidth = 31 + Caption = 'TBMain' + DisabledImages = ILMainDis + Images = ILMain + TabOrder = 1 + Wrapable = False + object TBPageFirst: TToolButton + Left = 0 + Top = 0 + Action = ACPageFirst + Grouped = True + ParentShowHint = False + ShowHint = True + end + object TBPagePrevious: TToolButton + Left = 31 + Top = 0 + Action = ACPagePrevious + Grouped = True + ParentShowHint = False + ShowHint = True + end + object TBPageNext: TToolButton + Left = 62 + Top = 0 + Action = ACPageNext + Grouped = True + ParentShowHint = False + ShowHint = True + end + object TBPageLast: TToolButton + Left = 93 + Top = 0 + Action = ACPageLast + Grouped = True + ParentShowHint = False + ShowHint = True + end + object ToolButton3: TToolButton + Left = 124 + Top = 0 + Width = 8 + Caption = 'ToolButton3' + ImageIndex = 2 + Style = tbsSeparator + end + object PNPage: TPanel + Left = 132 + Top = 0 + Width = 71 + Height = 30 + BevelOuter = bvNone + ParentBackground = False + TabOrder = 0 + object EDPage: TEdit + Left = 7 + Top = 4 + Width = 43 + Height = 21 + TabOrder = 0 + Text = '1' + OnExit = EDPageExit + end + object UDPage: TUpDown + Left = 50 + Top = 4 + Width = 15 + Height = 21 + Associate = EDPage + Min = 1 + Position = 1 + TabOrder = 1 + OnClick = UDPageClick + end + end + object ToolButton6: TToolButton + Left = 203 + Top = 0 + Width = 8 + Caption = 'ToolButton6' + ImageIndex = 3 + Style = tbsSeparator + end + object PNScale: TPanel + Left = 211 + Top = 0 + Width = 112 + Height = 30 + BevelOuter = bvNone + ParentBackground = False + ParentColor = True + TabOrder = 1 + object CoBScale: TComboBox + Left = 9 + Top = 4 + Width = 95 + Height = 21 + AutoComplete = False + DropDownCount = 16 + TabOrder = 0 + OnExit = CoBScaleExit + OnSelect = CoBScaleExit + Items.Strings = ( + '25 %' + '50 %' + '75 %' + '100 %' + '125 %' + '150 %' + '200 %' + '500 %' + 'whole page' + 'page width ' + ' ') + end + end + object ToolButton1: TToolButton + Left = 323 + Top = 0 + Width = 8 + Caption = 'ToolButton1' + ImageIndex = 4 + Style = tbsSeparator + end + object TBPrint: TToolButton + Left = 331 + Top = 0 + Action = ACPrint + ParentShowHint = False + ShowHint = True + end + object ToolButton4: TToolButton + Left = 362 + Top = 0 + Width = 8 + Caption = 'ToolButton4' + ImageIndex = 5 + Style = tbsSeparator + end + object TBClose: TToolButton + Left = 370 + Top = 0 + Action = ACClose + ParentShowHint = False + ShowHint = True + end + end + object Preview: TKPrintPreview + Left = 0 + Top = 30 + Width = 812 + Height = 584 + Align = alClient + Page = 0 + TabStop = True + TabOrder = 0 + OnChanged = PreviewChanged + end + object ILMain: TImageList + Height = 24 + Width = 24 + Left = 16 + Top = 52 + Bitmap = { + 494C010106000900040018001800FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 + 0000000000003600000028000000600000003000000001002000000000000048 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000A1C3C9008EACB10081979A007E9395007E9396007E9396007E93 + 96007E9496007E9496007E9496007E9496007E93960082999D0094B3B900A5C8 + CE00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000A8CCD300A8CBD200000000000000 + 0000000000000000000099B1B300FFF0C400FFE6BC00FFE6BC00FFE6BD00FFE7 + BE00FFE8BF00FFEAC300FFEAC300FFEBC500FFEFCA00FFE3C100A5C7CE000000 + 00000000000000000000A8CBD200A8CCD3000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000009ABBC10092B1B70088A1A6008691 + 9300848F91008F9B9F009D9A9100FFD4A400FFD0A300FFD1A400FFD1A700FFD4 + A900FFD5AE00FFD8B100FFD9B300FFDAB600FFDFBC00F6D6B800848B8B00848F + 920088929400889FA40093B2B8009ABBC1000000000000000000000000000000 + 00000000000000000000ACC3C700ACC3C7000000000000000000000000000000 + 000000000000000000000000000000000000ACC3C700ACC3C700000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000A6C9D0008DA7AD00B3B7B800D3D3 + D300D7D7D700BBBEC0006D625700EFBF9100EABC9100EABD9400EABE9600EAC1 + 9A00EAC39F00EAC5A200EAC6A500EAC8AA00EDCEB000D5B99F006A686600D5D6 + D700D2D2D200B7BABB008AA2A700A8CBD2000000000000000000000000000000 + 000000000000ACC3C7004646C1004646C100ACC3C70000000000000000000000 + 0000000000000000000000000000ACC3C7004646C1004646C100ACC3C7000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000008C9EA100D4D4D400D4D4 + D400D5D5D500BEC0C200554B4300BA947200B6937300B6937500B6957700B697 + 7B00B6987C00B6987E00B79A8000B79A8500BA9F8900A38B770058575600D8D4 + D700D2D0D100D0D0D0008C9EA100000000000000000000000000000000000000 + 0000ACC3C7004646C1007575DB007474DB004646C100ACC3C700000000000000 + 00000000000000000000ACC3C7004646C1007474DB007575DB004646C100ACC3 + C700000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000B2C3C700CBCBCB00D8D8 + D800D6D6D600CDCDCE0096919000B7A9A300B6A8A200B6A8A200B6A8A200B5A8 + A100B5A8A200B5A8A200B5A7A100B5A7A200B5A8A200AC9F9A009E989A009CC1 + B100AEC6BC00CBC7C900B2C3C700000000000000000000000000000000000000 + 00004646C1007575DB009898FF008E8EFF006A6ADB004646C100ACC3C7000000 + 000000000000ACC3C7004646C1006A6ADB008E8EFF009898FF007575DB004646 + C100000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000AABCC000CDCDCD00E1E0 + E000EBEAEB00E3E8E600EAF0EE00E4ECEB00E4ECEB00E4ECEB00E4ECEA00E4EC + EA00E4ECEA00E4ECEA00E4EBEA00E4EBEA00E3EBE900E4ECEA00EFF0EF00CEE0 + D900C8D4CF00CBC9CA00AABCC000000000000000000000000000000000000000 + 00004646C1007474DB008E8EFF007A7AFF008080FF006767DB004646C100ACC3 + C700ACC3C7004646C1006767DB008080FF007A7AFF008E8EFF007474DB004646 + C100000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000ABBDC000D6D2D400E7EE + EB006DBF9D0030A475003AA97B003AA97A003AA87A003AA87A003AA77A003AA8 + 79003AA879003AA779003BA77A003BA77A003BA77A003BA77A0030A272007DC4 + A600EDEFEE00D1CECF00ABBDC000000000000000000000000000000000000000 + 0000000000004646C1006A6ADB008080FF007575FF007B7BFF006161DB004646 + C1004646C1006161DB007B7BFF007575FF008080FF006A6ADB004646C1000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000ADC1C500E5DEE100C0E2 + D3002BB27F0047C89C0040C0920041C0920041C0920041C0920041C0920041C0 + 930041C0930041C0930041C0930041C0930041C0930040BF920047C99C002CAE + 7D00C5E2D400E2DBDE00ADC1C400000000000000000000000000000000000000 + 000000000000000000004646C1006767DB007B7BFF007070FF006E6EFF007272 + FF007272FF006E6EFF007070FF007B7BFF006767DB004646C100000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000AFC3C600EFE8EB00C0E5 + D7002BB483002AB281001BAB76001DAD79001DAD79001DAD79001DAD79001DAD + 79001DAD79001DAD79001DAD79001DAD79001DAD79001BAB76002AB281002CAF + 7F00C9E6DA00EEE7EB00B0C3C700000000000000000000000000000000000000 + 00000000000000000000000000004646C1006161DB006E6EFF006262FF005F5F + FF005F5FFF006262FF006E6EFF006161DB004646C10000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000B1C5C900F9F2F500BCE7 + D70033C2910038CB9C0024C6920026C8950026C8950026C8950026C8950026C8 + 950026C8950026C8950026C8950026C8950026C8950023C5920039CD9F0038BF + 9000C7E7D900FCF4F700B3C7CA00000000000000000000000000000000000000 + 0000000000000000000000000000000000004646C1007272FF005F5FFF005858 + FF005858FF005F5FFF007272FF004646C1000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000B3C8CC00FBF4F600B1E6 + D4003ACB9D0074F4CF006EF1CC006EF2CC006EF1CC006EF1CC006EF2CC006EF2 + CC006EF2CC006EF1CC006EF1CC006EF1CC006EF2CC006FF1CC0076F4D0003CC8 + 9900C5E7DA00FFF6FA00B7CACE00000000000000000000000000000000000000 + 0000000000000000000000000000ACC3C7004646C100B5B5FF00ABABFF00A8A8 + FF00A8A8FF00ABABFF00B5B5FF004646C100ACC3C70000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000B3C8CC00FBF4F600ADE7 + D4003BCFA1006AEFC80050D7AD0050D5AC0050D6AC0050D6AC0050D5AC0050D5 + AC0050D5AC0050D6AC0050D6AD0050D6AC0051D5AC004DD7AD0061ECC3003CCB + 9C00C4EADC00FFF6FA00B7CBCE00000000000000000000000000000000000000 + 00000000000000000000ACC3C7004646C1007C7CDB00BFBFFF00B9B9FF00B8B8 + FF00B8B8FF00B9B9FF00BFBFFF007C7CDB004646C100ACC3C700000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000B1C8CC00F6EDF000BBEC + DC0031D2A10047D5A600A9B58A00B8B58C00B5B68C00B5B68C00B5B68C00B5B6 + 8C00B5B68C00B5B68C00B5B68D00B5B68C00B8B58C00A8B78C0032CA99001AC2 + 8D00C9EFE100FBF1F400B3C9CD00000000000000000000000000000000000000 + 000000000000ACC3C7004646C1008383DB00CFCFFF00CBCBFF00CBCBFF00CCCC + FF00CCCCFF00CBCBFF00CBCBFF00CFCFFF008383DB004646C100ACC3C7000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000ABCED500BFC7CC009DCD + BE003AC199005ABB9A00EBC7A000FFCDA500FACCA400FACCA400FACCA400FACC + A400FACCA400FACCA400FACCA400FACCA400FECDA500EFC9A1005FBA990036BB + 9300A4CBC000C2C9CD00ACCDD400000000000000000000000000000000000000 + 0000ACC3C7004646C1008787DB00DCDCFF00D9D9FF00DBDBFF008585DB004646 + C1004646C1008585DB00DBDBFF00D9D9FF00DCDCFF008787DB004646C100ACC3 + C700000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000ACCC + D200ACCDD400A9CED300E6D2AE00FCD9B400F8D9B400F9D9B400F8D9B300F9D9 + B400F9D9B400F8D9B300F9D9B300F9D9B400FBDAB400EDD3B200ABCBD100ACCD + D400ABCED4000000000000000000000000000000000000000000000000000000 + 00004646C1008C8CDB00E9E9FF00E6E6FF00E7E7FF008A8ADB004646C1000000 + 0000000000004646C1008A8ADB00E7E7FF00E6E6FF00E9E9FF008C8CDB004646 + C100000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000AFCFD400F6D4B100F9DAB700FADAB600F9D9B600FADAB700F9DB + B700F9DBB700F9DAB700F9DAB700FADAB700FBDAB600F1D5B300ACCED4000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00004646C1008F8FDB00F3F3FF00F2F2FF008E8EDB004646C100000000000000 + 000000000000000000004646C1008E8EDB00F2F2FF00F3F3FF008F8FDB004646 + C100000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000AFCFD300F0D1B000FADDBB00FADCBA00FADCBA00FADDBA00F9DC + BA00FADDBA00FADCBB00F9DBBA00FADCBA00FADDBA00F3D4B300B0CFD3000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000004646C1009191DB009191DB004646C10000000000000000000000 + 00000000000000000000000000004646C1009191DB009191DB004646C1000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000AFCFD300EED0B000FADFBF00FADEBE00FADDBD00FADDBD00FADE + BE00FADEBE00FADDBD00FADEBD00FADEBE00FADEBF00F0D2B300B0CFD3000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000004646C1004646C1000000000000000000000000000000 + 0000000000000000000000000000000000004646C1004646C100000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000AFCED300EECEB100FBE1C300FADFC100FADFC100FBDFC100FBDF + C100FADFC200FBDFC100FADFC100FADFC100FBE0C200EFD1B200AFCFD3000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000AFCED300EECFB100FDE5C800FBE3C700FCE3C600FBE3C600FBE3 + C700FBE3C700FBE3C700FCE3C600FCE3C600FCE4C800EECFB200AFCED3000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000AFCED300EAC9AA00F0CCAC00F0CBAC00F0CBAB00F0CCAB00F0CB + AC00F0CBAC00F0CBAC00F0CBAB00F0CBAB00F0CCAC00EAC9AB00AFCED3000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000ACC3C700ACC3C700ACC3C700ACC3C7000000000000000000000000000000 + 00000000000000000000000000000000000000000000ACC3C700ACC3C7000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000ACC3C700ACC3C700ACC3C7000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000ACC3C700ACC3C700ACC3C7000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000ACC3C700ACC3C700000000000000000000000000000000000000 + 000000000000000000000000000000000000ACC3C700ACC3C700ACC3C700ACC3 + C700000000000000000000000000000000000000000000000000000000000000 + 00006BAE94006BAE94006BAE94006BAE94000000000000000000000000000000 + 0000000000000000000000000000ACC3C700ACC3C7006BAE94006BAE9400ACC3 + C700000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000ACC3C700ACC3C7006BAE94006BAE94006BAE9400ACC3 + C700000000000000000000000000000000000000000000000000000000000000 + 0000ACC3C7006BAE94006BAE94006BAE9400ACC3C700ACC3C700000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000ACC3C7006BAE94006BAE9400ACC3C700ACC3C70000000000000000000000 + 0000000000000000000000000000000000006BAE94006BAE94006BAE94006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400BFF2E500BFF2E5006BAE94000000000000000000000000000000 + 000000000000ACC3C700ACC3C7006BAE94006BAE94008ACAB40090CAB6006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000ACC3C700ACC3C7006BAE94006BAE940084C8B200AAEEDD008ECAB5006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE94008ECAB500AAEEDD0084C8B2006BAE94006BAE9400ACC3C700ACC3 + C700000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00006BAE940090CAB6008ACAB4006BAE94006BAE9400ACC3C700ACC3C7000000 + 0000000000000000000000000000000000006BAE9400BFF2E500BFF2E5006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400AAEEDD00AAEEDD006BAE9400000000000000000000000000ACC3 + C700ACC3C7006BAE94006BAE940081C8B00091E9D30093EAD400A8EEDC006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000ACC3C700ACC3 + C7006BAE94006BAE940081C8B0008FE9D20084E7CE008BE8D100A4EDDB006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400A4EDDB008BE8D10084E7CE008FE9D20081C8B0006BAE94006BAE + 9400ACC3C700ACC3C70000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400A8EEDC0093EAD40091E9D30081C8B0006BAE94006BAE9400ACC3 + C700ACC3C7000000000000000000000000006BAE9400AAEEDD00AAEEDD006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400A0ECD900A0ECD9006BAE940000000000ACC3C700ACC3C7006BAE + 94006BAE940081C8B0008EE9D20080E6CC0076E4C8007EE6CB0097EAD5006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000ACC3C700ACC3C7006BAE94006BAE + 940081C8B0008EE9D20080E6CC0075E4C8006FE3C50079E5C90095EAD4006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE940095EAD40079E5C9006FE3C50075E4C80080E6CC008EE9D20081C8 + B0006BAE94006BAE9400ACC3C700ACC3C7000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00006BAE940097EAD5007EE6CB0076E4C80080E6CC008EE9D20081C8B0006BAE + 94006BAE9400ACC3C700ACC3C700000000006BAE9400A0ECD900A0ECD9006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400A0ECD900A0ECD9006BAE9400ACC3C7006BAE94006BAE940081C8 + B0008EE9D20080E6CC0075E4C8006EE2C50069E1C30076E4C80091E9D3006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000ACC3C700ACC3C7006BAE94006BAE940081C8B0008EE9 + D20080E6CC0075E4C8006EE2C50069E1C30068E1C20075E4C80091E9D3006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE940091E9D30075E4C80068E1C20069E1C3006EE2C50075E4C80080E6 + CC008EE9D20081C8B0006BAE94006BAE9400ACC3C700ACC3C700000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00006BAE940091E9D30076E4C80069E1C3006EE2C50075E4C80080E6CC008EE9 + D20081C8B0006BAE94006BAE9400ACC3C7006BAE9400A0ECD900A0ECD9006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400A0ECD900A0ECD9006BAE94006BAE940081C8B0008EE9D20080E6 + CC0075E4C8006EE2C50069E1C30068E1C20067E1C20075E4C80091E9D3006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 000000000000ACC3C7006BAE94006BAE940081C8B0008EE9D20080E6CC0075E4 + C8006EE2C50069E1C30068E1C20067E1C20067E1C20075E4C80091E9D3006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE940091E9D30075E4C80067E1C20067E1C20068E1C20069E1C3006EE2 + C50075E4C80080E6CC008EE9D20081C8B0006BAE94006BAE9400ACC3C7000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00006BAE940091E9D30075E4C80067E1C20068E1C20069E1C3006EE2C50075E4 + C80080E6CC008EE9D20081C8B0006BAE94006BAE9400A0ECD900A0ECD9006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400A0ECD900A0ECD9006BAE940093EAD30080E6CC0075E4C8006EE2 + C50069E1C30068E1C20067E1C20067E1C20067E1C20075E4C80091E9D3006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 0000ACC3C7006BAE940087C9B20093EAD30080E6CC0075E4C8006EE2C50069E1 + C30068E1C20067E1C20067E1C20067E1C20067E1C20075E4C80091E9D3006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE940091E9D30075E4C80067E1C20067E1C20067E1C20067E1C20068E1 + C20069E1C3006EE2C50075E4C80080E6CC0093EAD30087C9B2006BAE9400ACC3 + C700000000000000000000000000000000000000000000000000000000000000 + 00006BAE940091E9D30075E4C80067E1C20067E1C20067E1C20068E1C20069E1 + C3006EE2C50075E4C80080E6CC0093EAD3006BAE9400A0ECD900A0ECD9006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400A0ECD900A0ECD9006BAE94007CE5CB006FE3C50069E1C30068E1 + C20067E1C20067E1C20067E1C20067E1C20067E1C20075E4C80091E9D3006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE94008CCAB50096EAD5007CE5CB006FE3C50069E1C30068E1C20067E1 + C20067E1C20067E1C20067E1C20067E1C20067E1C20075E4C80091E9D3006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE940091E9D30075E4C80067E1C20067E1C20067E1C20067E1C20067E1 + C20067E1C20068E1C20069E1C3006FE3C5007CE5CB0096EAD5008CCAB5006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE940091E9D30075E4C80067E1C20067E1C20067E1C20067E1C20067E1 + C20068E1C20069E1C3006FE3C5007CE5CB006BAE9400A0ECD900A0ECD9006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400D6F1EA00D6F1EA006BAE9400C6EBE200C0E9DF00BEE8DE00BDE8 + DD00BDE8DD00BDE8DD00BDE8DD00BDE8DD00BDE8DD00C3EAE000CFEEE6006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE94009CCBBA00D1EFE800C6EBE200C0E9DF00BEE8DE00BDE8DD00BDE8 + DD00BDE8DD00BDE8DD00BDE8DD00BDE8DD00BDE8DD00C3EAE000CFEEE6006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400CFEEE600C3EAE000BDE8DD00BDE8DD00BDE8DD00BDE8DD00BDE8 + DD00BDE8DD00BDE8DD00BEE8DE00C0E9DF00C6EBE200D1EFE8009CCBBA006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400CFEEE600C3EAE000BDE8DD00BDE8DD00BDE8DD00BDE8DD00BDE8 + DD00BDE8DD00BEE8DE00C0E9DF00C6EBE2006BAE9400D6F1EA00D6F1EA006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400DCF2ED00DCF2ED006BAE9400D8F1EA00D1EEE700CDEDE500CBEC + E300C9EBE200C8EBE200C8EBE200C8EBE200C8EBE200CDEDE500D7F1EA006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 0000000000006BAE94009CCBBA00D8F1EA00D1EEE700CDEDE500CBECE300C9EB + E200C8EBE200C8EBE200C8EBE200C8EBE200C8EBE200CDEDE500D7F1EA006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400D7F1EA00CDEDE500C8EBE200C8EBE200C8EBE200C8EBE200C8EB + E200C9EBE200CBECE300CDEDE500D1EEE700D8F1EA009CCBBA006BAE94000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400D7F1EA00CDEDE500C8EBE200C8EBE200C8EBE200C8EBE200C9EB + E200CBECE300CDEDE500D1EEE700D8F1EA006BAE9400DCF2ED00DCF2ED006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400E3F5F000E3F5F0006BAE94006BAE94009CCBBA00DEF3ED00DAF2 + EB00D7F1E900D5F0E800D4EFE700D3EFE700D3EFE700D7F1E900DFF3EE006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 000000000000000000006BAE94006BAE94009CCBBA00DEF3ED00DAF2EB00D7F1 + E900D5F0E800D4EFE700D3EFE700D3EFE700D3EFE700D7F1E900DFF3EE006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400DFF3EE00D7F1E900D3EFE700D3EFE700D3EFE700D4EFE700D5F0 + E800D7F1E900DAF2EB00DEF3ED009CCBBA006BAE94006BAE9400000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400DFF3EE00D7F1E900D3EFE700D3EFE700D4EFE700D5F0E800D7F1 + E900DAF2EB00DEF3ED009CCBBA006BAE94006BAE9400E3F5F000E3F5F0006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400EAF7F400EAF7F4006BAE9400000000006BAE94006BAE94009FCC + BC00E6F5F200E3F4F000E1F3EF00E0F3EE00DFF2ED00E1F3EF00E7F6F2006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000006BAE94006BAE94009FCCBC00E6F5 + F200E3F4F000E1F3EF00E0F3EE00DFF2ED00DEF2ED00E1F3EF00E7F6F2006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400E7F6F200E1F3EF00DEF2ED00DFF2ED00E0F3EE00E1F3EF00E3F4 + F000E6F5F2009FCCBC006BAE94006BAE94000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400E7F6F200E1F3EF00DFF2ED00E0F3EE00E1F3EF00E3F4F000E6F5 + F2009FCCBC006BAE94006BAE9400000000006BAE9400EAF7F400EAF7F4006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400F1F9F700F1F9F7006BAE94000000000000000000000000006BAE + 94006BAE9400A2CDBD00EEF8F600ECF7F500EAF7F400ECF7F500EFF9F7006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000006BAE94006BAE + 9400A2CDBD00EEF8F600ECF7F500EAF7F400E9F6F400EBF7F400EFF9F7006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400EFF9F700EBF7F400E9F6F400EAF7F400ECF7F500EEF8F600A2CD + BD006BAE94006BAE940000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400EFF9F700ECF7F500EAF7F400ECF7F500EEF8F600A2CDBD006BAE + 94006BAE94000000000000000000000000006BAE9400F1F9F700F1F9F7006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400F7FCFB00F7FCFB006BAE94000000000000000000000000000000 + 0000000000006BAE94006BAE9400A4CEBE00F5FBFA00F5FBFA00F7FCFB006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00006BAE94006BAE9400A4CEBE00F5FBFA00F4FBF900F4FBFA00F7FCFB006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400F7FCFB00F4FBFA00F4FBF900F5FBFA00A4CEBE006BAE94006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400F7FCFB00F5FBFA00F5FBFA00A4CEBE006BAE94006BAE94000000 + 0000000000000000000000000000000000006BAE9400F7FCFB00F7FCFB006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400FCFEFE00FCFEFE006BAE94000000000000000000000000000000 + 00000000000000000000000000006BAE94006BAE9400A7CFC000A7CFC0006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000006BAE94006BAE9400A7CFBF00FCFEFD00A7CFC0006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400A7CFC000FCFEFD00A7CFBF006BAE94006BAE9400000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00006BAE9400A7CFC000A7CFC0006BAE94006BAE940000000000000000000000 + 0000000000000000000000000000000000006BAE9400FCFEFE00FCFEFE006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 00006BAE94006BAE94006BAE94006BAE94000000000000000000000000000000 + 000000000000000000000000000000000000000000006BAE94006BAE94000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000006BAE94006BAE94006BAE94000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000006BAE94006BAE94006BAE94000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000006BAE94006BAE9400000000000000000000000000000000000000 + 0000000000000000000000000000000000006BAE94006BAE94006BAE94006BAE + 9400000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000424D3E000000000000003E000000 + 2800000060000000300000000100010000000000400200000000000000000000 + 000000000000000000000000FFFFFF00FFFFFFFFFFFF000000000000F8000FFF + FFFF0000000000003C001CFFFFFF000000000000000000FCFF3F000000000000 + 000000F87E1F000000000000800001F03C0F000000000000800001F0180F0000 + 00000000800001F0000F000000000000800001F8001F000000000000800001FC + 003F000000000000800001FE007F000000000000800001FF00FF000000000000 + 800001FE007F000000000000800001FC003F000000000000800001F8001F0000 + 00000000800001F0000F000000000000E00007F0180F000000000000F8001FF0 + 3C0F000000000000F8001FF87E1F000000000000F8001FFCFF3F000000000000 + F8001FFFFFFF000000000000F8001FFFFFFF000000000000F8001FFFFFFF0000 + 00000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF9FFFFF1FF8FFFFF9FF0F + F0FE0FFFFC0FF03FFFF07F0FF0F80FFFF00FF00FFFF01F0FF0E00FFFC00FF003 + FFF0070FF0800FFF000FF000FFF0010FF0000FFC000FF0003FF0000FF0000FF8 + 000FF0001FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000F + F0000FF0000FF0000FF0000FF0000FF8000FF0001FF0000FF0000FFC000FF000 + 3FF0000FF0800FFF000FF000FFF0010FF0E00FFFC00FF003FFF0070FF0F80FFF + F00FF00FFFF01F0FF0FE0FFFFC0FF03FFFF07F0FF0FF9FFFFF1FF8FFFFF9FF0F + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000 + 000000000000} + end + object ALMain: TActionList + Images = ILMain + Left = 56 + Top = 54 + object ACPageFirst: TAction + Hint = 'First page' + ImageIndex = 0 + OnExecute = ACPageFirstExecute + OnUpdate = ACPageFirstUpdate + end + object ACPagePrevious: TAction + Caption = 'Previous page' + Hint = 'Previous page' + ImageIndex = 1 + OnExecute = ACPagePreviousExecute + OnUpdate = ACPageFirstUpdate + end + object ACPageNext: TAction + Caption = 'Next page' + Hint = 'Next page' + ImageIndex = 2 + OnExecute = ACPageNextExecute + OnUpdate = ACPageNextUpdate + end + object ACPageLast: TAction + Caption = 'Last page' + Hint = 'Last page' + ImageIndex = 3 + OnExecute = ACPageLastExecute + OnUpdate = ACPageNextUpdate + end + object ACPrint: TAction + Caption = 'Print' + Hint = 'Print' + ImageIndex = 4 + OnExecute = ACPrintExecute + OnUpdate = ACPrintUpdate + end + object ACClose: TAction + Caption = 'Close' + Hint = 'Close preview' + ImageIndex = 5 + OnExecute = ACCloseExecute + OnUpdate = ACCloseUpdate + end + end + object ILMainDis: TImageList + Height = 24 + Width = 24 + Left = 96 + Top = 52 + Bitmap = { + 494C010106000900040018001800FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 + 0000000000003600000028000000600000003000000001002000000000000048 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000A1C3C9008EACB2007F979C007B9397007C9398007C9398007C93 + 98007C9398007C9498007C9498007C9498007C93980081999E0094B3B900A5C8 + CE00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000A8CCD300A8CBD200000000000000 + 0000000000000000000096B1B600E1E1E100DDDDDD00DDDDDD00DEDEDE00DEDE + DE00DFDFDF00E1E1E100E1E1E100E2E2E200E4E4E400E0E0E000A5C7CE000000 + 00000000000000000000A8CBD200A8CCD3000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000009ABBC10092B1B70088A1A6008691 + 9300848F9100919B9D00939A9B00D1D1D100D1D1D100D1D1D100D3D3D300D4D4 + D400D6D6D600D8D8D800D9D9D900DADADA00DDDDDD00D6D7D700838B8D00848F + 910088929400889FA40093B2B8009ABBC1000000000000000000000000000000 + 00000000000000000000AFC0C400AFC0C4000000000000000000000000000000 + 000000000000000000000000000000000000AFC0C400AFC0C400000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000A6C9D0008DA7AD00B3B7B800D3D3 + D300D7D7D700BDBDBD0062626200C0C0C000BDBDBD00BFBFBF00C0C0C000C2C2 + C200C4C4C400C6C6C600C7C7C700CACACA00CECECE00BABABA0068686800D6D6 + D600D2D2D200B7BABB008AA2A700A8CBD2000000000000000000000000000000 + 000000000000AFC0C4008383830083838300AFC0C40000000000000000000000 + 0000000000000000000000000000AFC0C4008383830083838300AFC0C4000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000008C9EA100D4D4D400D4D4 + D400D5D5D500C0C0C0004C4C4C00969696009494940095959500969696009898 + 9800999999009A9A9A009B9B9B009E9E9E00A1A1A1008D8D8D0057575700D6D6 + D600D1D1D100D0D0D0008C9EA100000000000000000000000000000000000000 + 0000AFC0C40083838300A8A8A800A7A7A70083838300AFC0C400000000000000 + 00000000000000000000AFC0C40083838300A7A7A700A8A8A80083838300AFC0 + C400000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000B2C3C700CBCBCB00D8D8 + D800D6D6D600CDCDCD0093939300ADADAD00ACACAC00ACACAC00ACACAC00ABAB + AB00ABABAB00ABABAB00ABABAB00ABABAB00ABABAB00A3A3A3009B9B9B00AEAE + AE00BABABA00C9C9C900B2C3C700000000000000000000000000000000000000 + 000083838300A8A8A800CBCBCB00C6C6C600A2A2A20083838300AFC0C4000000 + 000000000000AFC0C40083838300A2A2A200C6C6C600CBCBCB00A8A8A8008383 + 8300000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000AABCC000CDCDCD00E0E0 + E000EAEAEA00E5E5E500EDEDED00E8E8E800E8E8E800E8E8E800E8E8E800E8E8 + E800E8E8E800E8E8E800E7E7E700E7E7E700E7E7E700E8E8E800EFEFEF00D7D7 + D700CECECE00CACACA00AABCC000000000000000000000000000000000000000 + 000083838300A7A7A700C6C6C600BCBCBC00BFBFBF00A1A1A10083838300AFC0 + C400AFC0C40083838300A1A1A100BFBFBF00BCBCBC00C6C6C600A7A7A7008383 + 8300000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000ABBDC000D4D4D400EAEA + EA00969696006A6A6A0071717100717171007171710071717100707070007171 + 710071717100707070007171710071717100717171007171710069696900A0A0 + A000EEEEEE00CFCFCF00ABBDC000000000000000000000000000000000000000 + 00000000000083838300A2A2A200BFBFBF00BABABA00BDBDBD009E9E9E008383 + 8300838383009E9E9E00BDBDBD00BABABA00BFBFBF00A2A2A200838383000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000ADC1C500E1E1E100D1D1 + D1006E6E6E008787870080808000808080008080800080808000808080008080 + 800080808000808080008080800080808000808080007F7F7F00888888006D6D + 6D00D3D3D300DEDEDE00ADC1C400000000000000000000000000000000000000 + 0000000000000000000083838300A1A1A100BDBDBD00B7B7B700B6B6B600B8B8 + B800B8B8B800B6B6B600B7B7B700BDBDBD00A1A1A10083838300000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000AFC3C600EBEBEB00D2D2 + D2006F6F6F006E6E6E0063636300656565006565650065656500656565006565 + 65006565650065656500656565006565650065656500636363006E6E6E006D6D + 6D00D7D7D700EAEAEA00B0C3C700000000000000000000000000000000000000 + 0000000000000000000000000000838383009E9E9E00B6B6B600B0B0B000AFAF + AF00AFAFAF00B0B0B000B6B6B6009E9E9E008383830000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000B1C5C900F5F5F500D1D1 + D1007A7A7A008181810075757500777777007777770077777700777777007777 + 7700777777007777770077777700777777007777770074747400838383007B7B + 7B00D7D7D700F8F8F800B3C7CA00000000000000000000000000000000000000 + 00000000000000000000000000000000000083838300B8B8B800AFAFAF00ABAB + AB00ABABAB00AFAFAF00B8B8B800838383000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000B3C8CC00F7F7F700CBCB + CB0082828200B4B4B400AFAFAF00B0B0B000AFAFAF00AFAFAF00B0B0B000B0B0 + B000B0B0B000AFAFAF00AFAFAF00AFAFAF00B0B0B000B0B0B000B5B5B5008282 + 8200D6D6D600FAFAFA00B7CACE00000000000000000000000000000000000000 + 0000000000000000000000000000AFC0C40083838300DADADA00D5D5D500D3D3 + D300D3D3D300D5D5D500DADADA0083838300AFC0C40000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000B3C8CC00F7F7F700CACA + CA0085858500ACACAC0093939300929292009393930093939300929292009292 + 9200929292009393930093939300939393009393930092929200A6A6A6008383 + 8300D7D7D700FAFAFA00B7CBCE00000000000000000000000000000000000000 + 00000000000000000000AFC0C40083838300ABABAB00DFDFDF00DCDCDC00DBDB + DB00DBDBDB00DCDCDC00DFDFDF00ABABAB0083838300AFC0C400000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000B1C8CC00F1F1F100D3D3 + D300818181008E8E8E009F9F9F00A2A2A200A1A1A100A1A1A100A1A1A100A1A1 + A100A1A1A100A1A1A100A1A1A100A1A1A100A2A2A200A1A1A1007E7E7E006E6E + 6E00DCDCDC00F6F6F600B3C9CD00000000000000000000000000000000000000 + 000000000000AFC0C40083838300AFAFAF00E7E7E700E5E5E500E5E5E500E5E5 + E500E5E5E500E5E5E500E5E5E500E7E7E700AFAFAF0083838300AFC0C4000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000ABCED500BCCACD00B4B5 + B6007C7E7E00898C8C00C5C5C500D2D2D200CFCFCF00CFCFCF00CFCFCF00CFCF + CF00CFCFCF00CFCFCF00CFCFCF00CFCFCF00D1D1D100C8C8C8008C8E8E007779 + 7900B6B9B900BECBCE00ACCDD400000000000000000000000000000000000000 + 0000AFC0C40083838300B1B1B100EDEDED00ECECEC00EDEDED00B0B0B0008383 + 830083838300B0B0B000EDEDED00ECECEC00EDEDED00B1B1B10083838300AFC0 + C400000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000ACCC + D200ABCDD400AACCD300C8CACB00D8D8D800D6D6D600D6D6D600D5D5D500D6D6 + D600D6D6D600D5D5D500D6D6D600D6D6D600D7D7D700CED0D000ACCBD100ABCD + D400ABCED4000000000000000000000000000000000000000000000000000000 + 000083838300B3B3B300F4F4F400F2F2F200F3F3F300B2B2B200838383000000 + 00000000000083838300B2B2B200F3F3F300F2F2F200F4F4F400B3B3B3008383 + 8300000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000ADCFD500D1D4D400D8D8D800D8D8D800D7D7D700D8D8D800D8D8 + D800D8D8D800D8D8D800D8D8D800D8D8D800D8D8D800D0D3D300ACCED5000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000083838300B5B5B500F9F9F900F8F8F800B4B4B40083838300000000000000 + 0000000000000000000083838300B4B4B400F8F8F800F9F9F900B5B5B5008383 + 8300000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000ADCFD500CFD1D100DADADA00DADADA00DADADA00DADADA00D9D9 + D900DADADA00DADADA00D9D9D900DADADA00DADADA00D1D4D400AECFD6000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000083838300B6B6B600B6B6B6008383830000000000000000000000 + 000000000000000000000000000083838300B6B6B600B6B6B600838383000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000ADCFD500CED0D000DCDCDC00DCDCDC00DBDBDB00DBDBDB00DCDC + DC00DCDCDC00DBDBDB00DBDBDB00DCDCDC00DCDCDC00D0D3D300ADCFD6000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000083838300838383000000000000000000000000000000 + 0000000000000000000000000000000000008383830083838300000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000ADCFD500CED0D000DFDFDF00DDDDDD00DDDDDD00DEDEDE00DEDE + DE00DEDEDE00DEDEDE00DDDDDD00DDDDDD00DEDEDE00D0D2D200ADCFD5000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000ADCFD500CED0D000E2E2E200E1E1E100E1E1E100E0E0E000E1E1 + E100E1E1E100E1E1E100E1E1E100E1E1E100E2E2E200CFD1D100ADCFD5000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000ADCFD500C8CACB00CDCECE00CDCECE00CCCDCD00CCCDCD00CDCE + CE00CDCECE00CDCECE00CCCDCD00CCCDCD00CDCECE00C8CBCC00ADCFD5000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000AFC0C400AFC0C400AFC0C400AFC0C4000000000000000000000000000000 + 00000000000000000000000000000000000000000000AFC0C400AFC0C4000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000AFC0C400AFC0C400AFC0C4000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000AFC0C400AFC0C400AFC0C4000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000AFC0C400AFC0C400000000000000000000000000000000000000 + 000000000000000000000000000000000000AFC0C400AFC0C400AFC0C400AFC0 + C400000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C008C8C8C008C8C8C008C8C8C000000000000000000000000000000 + 0000000000000000000000000000AFC0C400AFC0C4008C8C8C008C8C8C00AFC0 + C400000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000AFC0C400AFC0C4008C8C8C008C8C8C008C8C8C00AFC0 + C400000000000000000000000000000000000000000000000000000000000000 + 0000AFC0C4008C8C8C008C8C8C008C8C8C00AFC0C400AFC0C400000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000AFC0C4008C8C8C008C8C8C00AFC0C400AFC0C40000000000000000000000 + 0000000000000000000000000000000000008C8C8C008C8C8C008C8C8C008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00D8D8D800D8D8D8008C8C8C000000000000000000000000000000 + 000000000000AFC0C400AFC0C4008C8C8C008C8C8C00AAAAAA00ADADAD008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000AFC0C400AFC0C4008C8C8C008C8C8C00A6A6A600CCCCCC00ACACAC008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00ACACAC00CCCCCC00A6A6A6008C8C8C008C8C8C00AFC0C400AFC0 + C400000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00ADADAD00AAAAAA008C8C8C008C8C8C00AFC0C400AFC0C4000000 + 0000000000000000000000000000000000008C8C8C00D8D8D800D8D8D8008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00CCCCCC00CCCCCC008C8C8C00000000000000000000000000AFC0 + C400AFC0C4008C8C8C008C8C8C00A4A4A400BDBDBD00BEBEBE00CBCBCB008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000AFC0C400AFC0 + C4008C8C8C008C8C8C00A4A4A400BCBCBC00B5B5B500B9B9B900C8C8C8008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00C8C8C800B9B9B900B5B5B500BCBCBC00A4A4A4008C8C8C008C8C + 8C00AFC0C400AFC0C40000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00CBCBCB00BEBEBE00BDBDBD00A4A4A4008C8C8C008C8C8C00AFC0 + C400AFC0C4000000000000000000000000008C8C8C00CCCCCC00CCCCCC008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00C6C6C600C6C6C6008C8C8C0000000000AFC0C400AFC0C4008C8C + 8C008C8C8C00A4A4A400BBBBBB00B3B3B300ADADAD00B2B2B200C0C0C0008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000AFC0C400AFC0C4008C8C8C008C8C + 8C00A4A4A400BBBBBB00B3B3B300ACACAC00A9A9A900AFAFAF00BFBFBF008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00BFBFBF00AFAFAF00A9A9A900ACACAC00B3B3B300BBBBBB00A4A4 + A4008C8C8C008C8C8C00AFC0C400AFC0C4000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00C0C0C000B2B2B200ADADAD00B3B3B300BBBBBB00A4A4A4008C8C + 8C008C8C8C00AFC0C400AFC0C400000000008C8C8C00C6C6C600C6C6C6008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00C6C6C600C6C6C6008C8C8C00AFC0C4008C8C8C008C8C8C00A4A4 + A400BBBBBB00B3B3B300ACACAC00A8A8A800A5A5A500ADADAD00BDBDBD008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000AFC0C400AFC0C4008C8C8C008C8C8C00A4A4A400BBBB + BB00B3B3B300ACACAC00A8A8A800A5A5A500A4A4A400ACACAC00BDBDBD008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00BDBDBD00ACACAC00A4A4A400A5A5A500A8A8A800ACACAC00B3B3 + B300BBBBBB00A4A4A4008C8C8C008C8C8C00AFC0C400AFC0C400000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00BDBDBD00ADADAD00A5A5A500A8A8A800ACACAC00B3B3B300BBBB + BB00A4A4A4008C8C8C008C8C8C00AFC0C4008C8C8C00C6C6C600C6C6C6008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00C6C6C600C6C6C6008C8C8C008C8C8C00A4A4A400BBBBBB00B3B3 + B300ACACAC00A8A8A800A5A5A500A4A4A400A4A4A400ACACAC00BDBDBD008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 000000000000AFC0C4008C8C8C008C8C8C00A4A4A400BBBBBB00B3B3B300ACAC + AC00A8A8A800A5A5A500A4A4A400A4A4A400A4A4A400ACACAC00BDBDBD008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00BDBDBD00ACACAC00A4A4A400A4A4A400A4A4A400A5A5A500A8A8 + A800ACACAC00B3B3B300BBBBBB00A4A4A4008C8C8C008C8C8C00AFC0C4000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00BDBDBD00ACACAC00A4A4A400A4A4A400A5A5A500A8A8A800ACAC + AC00B3B3B300BBBBBB00A4A4A4008C8C8C008C8C8C00C6C6C600C6C6C6008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00C6C6C600C6C6C6008C8C8C00BEBEBE00B3B3B300ACACAC00A8A8 + A800A5A5A500A4A4A400A4A4A400A4A4A400A4A4A400ACACAC00BDBDBD008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 0000AFC0C4008C8C8C00A8A8A800BEBEBE00B3B3B300ACACAC00A8A8A800A5A5 + A500A4A4A400A4A4A400A4A4A400A4A4A400A4A4A400ACACAC00BDBDBD008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00BDBDBD00ACACAC00A4A4A400A4A4A400A4A4A400A4A4A400A4A4 + A400A5A5A500A8A8A800ACACAC00B3B3B300BEBEBE00A8A8A8008C8C8C00AFC0 + C400000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00BDBDBD00ACACAC00A4A4A400A4A4A400A4A4A400A4A4A400A5A5 + A500A8A8A800ACACAC00B3B3B300BEBEBE008C8C8C00C6C6C600C6C6C6008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00C6C6C600C6C6C6008C8C8C00B0B0B000A9A9A900A5A5A500A4A4 + A400A4A4A400A4A4A400A4A4A400A4A4A400A4A4A400ACACAC00BDBDBD008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00ABABAB00C0C0C000B0B0B000A9A9A900A5A5A500A4A4A400A4A4 + A400A4A4A400A4A4A400A4A4A400A4A4A400A4A4A400ACACAC00BDBDBD008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00BDBDBD00ACACAC00A4A4A400A4A4A400A4A4A400A4A4A400A4A4 + A400A4A4A400A4A4A400A5A5A500A9A9A900B0B0B000C0C0C000ABABAB008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00BDBDBD00ACACAC00A4A4A400A4A4A400A4A4A400A4A4A400A4A4 + A400A4A4A400A5A5A500A9A9A900B0B0B0008C8C8C00C6C6C600C6C6C6008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00E3E3E300E3E3E3008C8C8C00D8D8D800D4D4D400D3D3D300D2D2 + D200D2D2D200D2D2D200D2D2D200D2D2D200D2D2D200D6D6D600DEDEDE008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00B3B3B300E0E0E000D8D8D800D4D4D400D3D3D300D2D2D200D2D2 + D200D2D2D200D2D2D200D2D2D200D2D2D200D2D2D200D6D6D600DEDEDE008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00DEDEDE00D6D6D600D2D2D200D2D2D200D2D2D200D2D2D200D2D2 + D200D2D2D200D2D2D200D3D3D300D4D4D400D8D8D800E0E0E000B3B3B3008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00DEDEDE00D6D6D600D2D2D200D2D2D200D2D2D200D2D2D200D2D2 + D200D2D2D200D3D3D300D4D4D400D8D8D8008C8C8C00E3E3E300E3E3E3008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00E7E7E700E7E7E7008C8C8C00E4E4E400DFDFDF00DDDDDD00DBDB + DB00DADADA00D9D9D900D9D9D900D9D9D900D9D9D900DDDDDD00E4E4E4008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 0000000000008C8C8C00B3B3B300E4E4E400DFDFDF00DDDDDD00DBDBDB00DADA + DA00D9D9D900D9D9D900D9D9D900D9D9D900D9D9D900DDDDDD00E4E4E4008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00E4E4E400DDDDDD00D9D9D900D9D9D900D9D9D900D9D9D900D9D9 + D900DADADA00DBDBDB00DDDDDD00DFDFDF00E4E4E400B3B3B3008C8C8C000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00E4E4E400DDDDDD00D9D9D900D9D9D900D9D9D900D9D9D900DADA + DA00DBDBDB00DDDDDD00DFDFDF00E4E4E4008C8C8C00E7E7E700E7E7E7008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00ECECEC00ECECEC008C8C8C008C8C8C00B3B3B300E8E8E800E6E6 + E600E4E4E400E2E2E200E1E1E100E1E1E100E1E1E100E4E4E400E9E9E9008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 000000000000000000008C8C8C008C8C8C00B3B3B300E8E8E800E6E6E600E4E4 + E400E2E2E200E1E1E100E1E1E100E1E1E100E1E1E100E4E4E400E9E9E9008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00E9E9E900E4E4E400E1E1E100E1E1E100E1E1E100E1E1E100E2E2 + E200E4E4E400E6E6E600E8E8E800B3B3B3008C8C8C008C8C8C00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00E9E9E900E4E4E400E1E1E100E1E1E100E1E1E100E2E2E200E4E4 + E400E6E6E600E8E8E800B3B3B3008C8C8C008C8C8C00ECECEC00ECECEC008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00F0F0F000F0F0F0008C8C8C00000000008C8C8C008C8C8C00B5B5 + B500EDEDED00EBEBEB00EAEAEA00E9E9E900E8E8E800EAEAEA00EEEEEE008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000008C8C8C008C8C8C00B5B5B500EDED + ED00EBEBEB00EAEAEA00E9E9E900E8E8E800E8E8E800EAEAEA00EEEEEE008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00EEEEEE00EAEAEA00E8E8E800E8E8E800E9E9E900EAEAEA00EBEB + EB00EDEDED00B5B5B5008C8C8C008C8C8C000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00EEEEEE00EAEAEA00E8E8E800E9E9E900EAEAEA00EBEBEB00EDED + ED00B5B5B5008C8C8C008C8C8C00000000008C8C8C00F0F0F000F0F0F0008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00F5F5F500F5F5F5008C8C8C000000000000000000000000008C8C + 8C008C8C8C00B7B7B700F3F3F300F1F1F100F0F0F000F1F1F100F4F4F4008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000008C8C8C008C8C + 8C00B7B7B700F3F3F300F1F1F100F0F0F000EFEFEF00F1F1F100F4F4F4008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00F4F4F400F1F1F100EFEFEF00F0F0F000F1F1F100F3F3F300B7B7 + B7008C8C8C008C8C8C0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00F4F4F400F1F1F100F0F0F000F1F1F100F3F3F300B7B7B7008C8C + 8C008C8C8C000000000000000000000000008C8C8C00F5F5F500F5F5F5008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00F9F9F900F9F9F9008C8C8C000000000000000000000000000000 + 0000000000008C8C8C008C8C8C00B9B9B900F8F8F800F8F8F800F9F9F9008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C008C8C8C00B9B9B900F8F8F800F7F7F700F7F7F700F9F9F9008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00F9F9F900F7F7F700F7F7F700F8F8F800B9B9B9008C8C8C008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00F9F9F900F8F8F800F8F8F800B9B9B9008C8C8C008C8C8C000000 + 0000000000000000000000000000000000008C8C8C00F9F9F900F9F9F9008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00FDFDFD00FDFDFD008C8C8C000000000000000000000000000000 + 00000000000000000000000000008C8C8C008C8C8C00BBBBBB00BBBBBB008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000008C8C8C008C8C8C00BBBBBB00FDFDFD00BBBBBB008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00BBBBBB00FDFDFD00BBBBBB008C8C8C008C8C8C00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C00BBBBBB00BBBBBB008C8C8C008C8C8C0000000000000000000000 + 0000000000000000000000000000000000008C8C8C00FDFDFD00FDFDFD008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 00008C8C8C008C8C8C008C8C8C008C8C8C000000000000000000000000000000 + 000000000000000000000000000000000000000000008C8C8C008C8C8C000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000008C8C8C008C8C8C008C8C8C000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000008C8C8C008C8C8C008C8C8C000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000008C8C8C008C8C8C00000000000000000000000000000000000000 + 0000000000000000000000000000000000008C8C8C008C8C8C008C8C8C008C8C + 8C00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000424D3E000000000000003E000000 + 2800000060000000300000000100010000000000400200000000000000000000 + 000000000000000000000000FFFFFF00FFFFFFFFFFFF000000000000F8000FFF + FFFF0000000000003C001CFFFFFF000000000000000000FCFF3F000000000000 + 000000F87E1F000000000000800001F03C0F000000000000800001F0180F0000 + 00000000800001F0000F000000000000800001F8001F000000000000800001FC + 003F000000000000800001FE007F000000000000800001FF00FF000000000000 + 800001FE007F000000000000800001FC003F000000000000800001F8001F0000 + 00000000800001F0000F000000000000E00007F0180F000000000000F8001FF0 + 3C0F000000000000F8001FF87E1F000000000000F8001FFCFF3F000000000000 + F8001FFFFFFF000000000000F8001FFFFFFF000000000000F8001FFFFFFF0000 + 00000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF9FFFFF1FF8FFFFF9FF0F + F0FE0FFFFC0FF03FFFF07F0FF0F80FFFF00FF00FFFF01F0FF0E00FFFC00FF003 + FFF0070FF0800FFF000FF000FFF0010FF0000FFC000FF0003FF0000FF0000FF8 + 000FF0001FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000F + F0000FF0000FF0000FF0000FF0000FF8000FF0001FF0000FF0000FFC000FF000 + 3FF0000FF0800FFF000FF000FFF0010FF0E00FFFC00FF003FFF0070FF0F80FFF + F00FF00FFFF01F0FF0FE0FFFFC0FF03FFFF07F0FF0FF9FFFFF1FF8FFFFF9FF0F + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000 + 000000000000} + end +end diff --git a/components/kcontrols/source/kprintpreview.lfm b/components/kcontrols/source/kprintpreview.lfm new file mode 100755 index 000000000..b47e15c0d --- /dev/null +++ b/components/kcontrols/source/kprintpreview.lfm @@ -0,0 +1,1150 @@ +object KPrintPreviewForm: TKPrintPreviewForm + Left = 1112 + Height = 660 + Top = 476 + Width = 800 + ActiveControl = Preview + Caption = 'Print Preview' + ClientHeight = 660 + ClientWidth = 800 + Font.Height = -11 + Font.Name = 'Tahoma' + Icon.Data = { + 7E04000000000100010010100000010020006804000016000000280000001000 + 0000200000000100200000000000000400006400000064000000000000000000 + 000000000025161310C60F0C0AB80C0C0C8F1514149815141498151414981514 + 1498151414981514149815141498151414980C0C0C8F00000029000000000000 + 000015120FC295887BFF8F8378FFB9B0A8FFF1F0EEFFF1F0EEFFF1F0EEFFF1F0 + EEFFF1F0EEFFF1F0EEFFF1F0EEFFF1F0EEFFEAE8E6FF51504FEA0000000C0000 + 00000C0A08AE867B70FFD2CCC6FFB7ADA3FFC1BCB6FFE3E3E3FFE0E0E0FFDFDF + DFFFFEFEFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5A3A1FF000000350000 + 00000000000913110FBBA59C93FFE1DDD9FFB6ACA2FFBAB4AFFFA69E97FFA297 + 8CFFA1968BFFA9A29BFFD1D0CEFFF1F1F1FFFEFEFEFFA8A7A5FF000000360000 + 000000000000000000368B8580FFBAB0A6FFD4CEC7FF9A8D7EFFAA9E89FFC8C0 + B0FFCCC3B3FFBCAE95FF978B7CFFE2DEDBFFFDFDFDFFA9A8A7FF000000360000 + 00000000000000000036AAA9A8FFE0DCD8FFA29586FFA9986CFFC6BA91FFD0C7 + A9FFD1C9AAFFC5B990FFAA986CFFA4998CFFF7F6F5FFAAA9A8FF000000360000 + 00000000000000000036ABAAA9FFD6D1CCFFA0906EFFAD9C60FFB9AC78FFBFB4 + 85FFBBB082FFBAAE79FFAB9A5EFFA99874FFD9D4D0FFABAAA9FF000000360000 + 00000000000000000036ACABA9FFD1CBC4FFA18D5AFFB7A45CFFB8A866FFB8A8 + 69FFB9A969FFBBA963FFB6A154FFA7925DFFD4CEC8FFABA9A8FF000000360000 + 00000000000000000036ACABAAFFDAD5D0FFAB9A6EFFC7B778FFCABB80FFCBBD + 85FFC9BA7FFFC4B371FFB4A157FFA89462FFDBD5D1FFA7A5A3FF000000360000 + 00000000000000000036ADACABFFEBE9E6FFB4A892FFC5B990FFD7CDA8FFD9D0 + AAFFD8CFAAFFD8CEA8FFC2B58CFFBAAF9AFFE4E0DCFF9C9894FF000000360000 + 00000000000000000036ADACABFFF1EFEDFFCFCBC8FFB9AC91FFD3C8A7FFF2EE + E1FFF2EEE0FFD2C6A4FFBAAD93FFC9C4BFFFD5CEC7FF817971FF000000360000 + 00000000000000000036ADADACFFEDEBE9FFB9B7B5FFC3C1BEFFB8B1A8FFA59B + 86FFA89D87FFCCC5BBFFDFD9D4FFE5E1DDFFE4E0DCFF514E4BEC0000001B0000 + 00000000000000000036AEADACFFEAE7E4FF979694FFB6B4B1FFACAAA7FFA8A6 + A4FFA2A09EFFDAD5CFFFE8E5E2FFE6E3E0FF656564EC00000031000000000000 + 00000000000000000035ADACABFFE6E3DFFFE6E3DFFFE6E3DFFFE6E3DFFFE4E1 + DDFFDED9D4FFD3CCC4FFEBE9E7FF646464EB0000002E00000000000000000000 + 0000000000000000000C5B5B5BEAEFEEECFFF0EEECFFF0EEEBFFEEEBE9FFE7E3 + DFFFD4CDC6FFBDB3A8FF646464EB0000002F0000000000000000000000000000 + 00000000000000000000000000290E0E0E8F1717179817171798171717981615 + 1598131211980C0B0A980000002E000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000 + } + KeyPreview = True + OnCreate = FormCreate + OnKeyDown = FormKeyDown + OnShow = FormShow + Position = poScreenCenter + LCLVersion = '0.9.29' + object ToBMain: TToolBar + Left = 0 + Top = 0 + Width = 800 + AutoSize = True + ButtonHeight = 30 + ButtonWidth = 31 + Caption = 'TBMain' + DisabledImages = ILMainDis + Images = ILMain + TabOrder = 0 + Wrapable = False + object TBPageFirst: TToolButton + Left = 1 + Top = 2 + Action = ACPageFirst + Grouped = True + ParentShowHint = False + ShowHint = True + end + object TBPagePrevious: TToolButton + Left = 32 + Top = 2 + Action = ACPagePrevious + Grouped = True + ParentShowHint = False + ShowHint = True + end + object TBPageNext: TToolButton + Left = 63 + Top = 2 + Action = ACPageNext + Grouped = True + ParentShowHint = False + ShowHint = True + end + object TBPageLast: TToolButton + Left = 94 + Top = 2 + Action = ACPageLast + Grouped = True + ParentShowHint = False + ShowHint = True + end + object ToolButton3: TToolButton + Left = 125 + Top = 2 + Width = 8 + Caption = 'ToolButton3' + ImageIndex = 2 + Style = tbsSeparator + end + object ToolButton6: TToolButton + Left = 198 + Top = 2 + Width = 8 + Caption = 'ToolButton6' + ImageIndex = 3 + Style = tbsSeparator + end + object TBPrint: TToolButton + Left = 333 + Top = 2 + Action = ACPrint + ParentShowHint = False + ShowHint = True + end + object ToolButton4: TToolButton + Left = 364 + Top = 2 + Width = 8 + Caption = 'ToolButton4' + ImageIndex = 5 + Style = tbsSeparator + end + object TBClose: TToolButton + Left = 372 + Top = 2 + Action = ACClose + ParentShowHint = False + ShowHint = True + end + object PNPage: TPanel + Left = 133 + Height = 30 + Top = 2 + Width = 65 + BevelOuter = bvNone + ClientHeight = 30 + ClientWidth = 65 + TabOrder = 0 + object EDPage: TEdit + Left = 4 + Height = 21 + Top = 4 + Width = 42 + OnExit = EDPageExit + TabOrder = 0 + Text = '1' + end + object UDPage: TUpDown + Left = 46 + Height = 21 + Top = 4 + Width = 15 + Associate = EDPage + Min = 1 + Position = 1 + TabOrder = 1 + Wrap = False + OnClick = UDPageClick + end + end + object PNScale: TPanel + Left = 206 + Height = 30 + Top = 2 + Width = 120 + BevelOuter = bvNone + ClientHeight = 30 + ClientWidth = 120 + TabOrder = 1 + object CoBScale: TComboBox + Left = 2 + Height = 21 + Top = 4 + Width = 115 + DropDownCount = 16 + ItemHeight = 13 + Items.Strings = ( + '25 %' + '50 %' + '75 %' + '100 %' + '125 %' + '150 %' + '200 %' + '500 %' + 'Whole Page' + 'Page Width' + ) + OnExit = CoBScaleExit + OnSelect = CoBScaleExit + TabOrder = 0 + end + end + object ToolButton1: TToolButton + Left = 326 + Top = 2 + Width = 7 + Caption = 'ToolButton1' + Style = tbsSeparator + end + end + object Preview: TKPrintPreview + Left = 0 + Height = 628 + Top = 32 + Width = 800 + Align = alClient + Page = 0 + TabStop = True + TabOrder = 1 + OnChanged = PreviewChanged + end + object ILMain: TImageList + Height = 24 + Width = 24 + left = 16 + top = 54 + Bitmap = { + 4C69060000001800000018000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF6BAE94FF6BAE94FF6BAE94FFADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B8006BAE94FF6BAE94FFADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFFCFEFEFFFCFEFEFF6BAE94FFADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B8006BAE94FF6BAE94FFA7CFC0FFA7CFC0FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFF7FCFBFFF7FCFBFF6BAE94FFADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B8006BAE94FF6BAE94FFA4CEBEFFF5FBFAFFF5FBFAFFF7FCFBFF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFF1F9F7FFF1F9F7FF6BAE94FFADB7B800ADB7B800ADB7B8006BAE94FF6BAE + 94FFA2CDBDFFEEF8F6FFECF7F5FFEAF7F4FFECF7F5FFEFF9F7FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFEAF7F4FFEAF7F4FF6BAE94FFADB7B8006BAE94FF6BAE94FF9FCCBCFFE6F5 + F2FFE3F4F0FFE1F3EFFFE0F3EEFFDFF2EDFFE1F3EFFFE7F6F2FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFE3F5F0FFE3F5F0FF6BAE94FF6BAE94FF9CCBBAFFDEF3EDFFDAF2EBFFD7F1 + E9FFD5F0E8FFD4EFE7FFD3EFE7FFD3EFE7FFD7F1E9FFDFF3EEFF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFDCF2EDFFDCF2EDFF6BAE94FFD8F1EAFFD1EEE7FFCDEDE5FFCBECE3FFC9EB + E2FFC8EBE2FFC8EBE2FFC8EBE2FFC8EBE2FFCDEDE5FFD7F1EAFF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFD6F1EAFFD6F1EAFF6BAE94FFC6EBE2FFC0E9DFFFBEE8DEFFBDE8DDFFBDE8 + DDFFBDE8DDFFBDE8DDFFBDE8DDFFBDE8DDFFC3EAE0FFCFEEE6FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFA0ECD9FFA0ECD9FF6BAE94FF7CE5CBFF6FE3C5FF69E1C3FF68E1C2FF67E1 + C2FF67E1C2FF67E1C2FF67E1C2FF67E1C2FF75E4C8FF91E9D3FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFA0ECD9FFA0ECD9FF6BAE94FF93EAD3FF80E6CCFF75E4C8FF6EE2C5FF69E1 + C3FF68E1C2FF67E1C2FF67E1C2FF67E1C2FF75E4C8FF91E9D3FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFA0ECD9FFA0ECD9FF6BAE94FF6BAE94FF81C8B0FF8EE9D2FF80E6CCFF75E4 + C8FF6EE2C5FF69E1C3FF68E1C2FF67E1C2FF75E4C8FF91E9D3FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFA0ECD9FFA0ECD9FF6BAE94FFADB7B8806BAE94FF6BAE94FF81C8B0FF8EE9 + D2FF80E6CCFF75E4C8FF6EE2C5FF69E1C3FF76E4C8FF91E9D3FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFA0ECD9FFA0ECD9FF6BAE94FFADB7B800ADB7B880ADB7B8806BAE94FF6BAE + 94FF81C8B0FF8EE9D2FF80E6CCFF76E4C8FF7EE6CBFF97EAD5FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFAAEEDDFFAAEEDDFF6BAE94FFADB7B800ADB7B800ADB7B800ADB7B880ADB7 + B8806BAE94FF6BAE94FF81C8B0FF91E9D3FF93EAD4FFA8EEDCFF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFBFF2E5FFBFF2E5FF6BAE94FFADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B880ADB7B8806BAE94FF6BAE94FF8ACAB4FF90CAB6FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF6BAE94FF6BAE94FF6BAE94FFADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B880ADB7B8806BAE94FF6BAE94FFADB7B880FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B880ADB7B880ADB7B880ADB7B880ADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B880ADB7B880ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B8006BAE94FF6BAE94FF6BAE94FFADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B8006BAE94FF6BAE94FFA7CFBFFFFCFEFDFFA7CFC0FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B8006BAE + 94FF6BAE94FFA4CEBEFFF5FBFAFFF4FBF9FFF4FBFAFFF7FCFBFF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B8006BAE94FF6BAE94FFA2CD + BDFFEEF8F6FFECF7F5FFEAF7F4FFE9F6F4FFEBF7F4FFEFF9F7FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B800ADB7B8006BAE94FF6BAE94FF9FCCBCFFE6F5F2FFE3F4 + F0FFE1F3EFFFE0F3EEFFDFF2EDFFDEF2EDFFE1F3EFFFE7F6F2FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B8006BAE94FF6BAE94FF9CCBBAFFDEF3EDFFDAF2EBFFD7F1E9FFD5F0 + E8FFD4EFE7FFD3EFE7FFD3EFE7FFD3EFE7FFD7F1E9FFDFF3EEFF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B8006BAE94FF9CCBBAFFD8F1EAFFD1EEE7FFCDEDE5FFCBECE3FFC9EBE2FFC8EB + E2FFC8EBE2FFC8EBE2FFC8EBE2FFC8EBE2FFCDEDE5FFD7F1EAFF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF9CCBBAFFD1EFE8FFC6EBE2FFC0E9DFFFBEE8DEFFBDE8DDFFBDE8DDFFBDE8 + DDFFBDE8DDFFBDE8DDFFBDE8DDFFBDE8DDFFC3EAE0FFCFEEE6FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF8CCAB5FF96EAD5FF7CE5CBFF6FE3C5FF69E1C3FF68E1C2FF67E1C2FF67E1 + C2FF67E1C2FF67E1C2FF67E1C2FF67E1C2FF75E4C8FF91E9D3FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B8806BAE94FF87C9B2FF93EAD3FF80E6CCFF75E4C8FF6EE2C5FF69E1C3FF68E1 + C2FF67E1C2FF67E1C2FF67E1C2FF67E1C2FF75E4C8FF91E9D3FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B8806BAE94FF6BAE94FF81C8B0FF8EE9D2FF80E6CCFF75E4C8FF6EE2 + C5FF69E1C3FF68E1C2FF67E1C2FF67E1C2FF75E4C8FF91E9D3FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B880ADB7B8806BAE94FF6BAE94FF81C8B0FF8EE9D2FF80E6 + CCFF75E4C8FF6EE2C5FF69E1C3FF68E1C2FF75E4C8FF91E9D3FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B880ADB7B8806BAE94FF6BAE94FF81C8 + B0FF8EE9D2FF80E6CCFF75E4C8FF6FE3C5FF79E5C9FF95EAD4FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B880ADB7B8806BAE + 94FF6BAE94FF81C8B0FF8FE9D2FF84E7CEFF8BE8D1FFA4EDDBFF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B880ADB7B8806BAE94FF6BAE94FF84C8B2FFAAEEDDFF8ECAB5FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B880ADB7B8806BAE94FF6BAE94FF6BAE94FFADB7B880FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B880ADB7B880ADB7B880ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B8006BAE94FF6BAE94FF6BAE94FFADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFA7CFC0FFFCFEFDFFA7CFBFFF6BAE94FF6BAE94FFADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFF7FCFBFFF4FBFAFFF4FBF9FFF5FBFAFFA4CEBEFF6BAE94FF6BAE94FFADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFEFF9F7FFEBF7F4FFE9F6F4FFEAF7F4FFECF7F5FFEEF8F6FFA2CDBDFF6BAE + 94FF6BAE94FFADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFE7F6F2FFE1F3EFFFDEF2EDFFDFF2EDFFE0F3EEFFE1F3EFFFE3F4F0FFE6F5 + F2FF9FCCBCFF6BAE94FF6BAE94FFADB7B800ADB7B800ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFDFF3EEFFD7F1E9FFD3EFE7FFD3EFE7FFD3EFE7FFD4EFE7FFD5F0E8FFD7F1 + E9FFDAF2EBFFDEF3EDFF9CCBBAFF6BAE94FF6BAE94FFADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFD7F1EAFFCDEDE5FFC8EBE2FFC8EBE2FFC8EBE2FFC8EBE2FFC8EBE2FFC9EB + E2FFCBECE3FFCDEDE5FFD1EEE7FFD8F1EAFF9CCBBAFF6BAE94FFADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFCFEEE6FFC3EAE0FFBDE8DDFFBDE8DDFFBDE8DDFFBDE8DDFFBDE8DDFFBDE8 + DDFFBDE8DDFFBEE8DEFFC0E9DFFFC6EBE2FFD1EFE8FF9CCBBAFF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF91E9D3FF75E4C8FF67E1C2FF67E1C2FF67E1C2FF67E1C2FF67E1C2FF67E1 + C2FF68E1C2FF69E1C3FF6FE3C5FF7CE5CBFF96EAD5FF8CCAB5FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF91E9D3FF75E4C8FF67E1C2FF67E1C2FF67E1C2FF67E1C2FF68E1C2FF69E1 + C3FF6EE2C5FF75E4C8FF80E6CCFF93EAD3FF87C9B2FF6BAE94FFADB7B880FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF91E9D3FF75E4C8FF67E1C2FF67E1C2FF68E1C2FF69E1C3FF6EE2C5FF75E4 + C8FF80E6CCFF8EE9D2FF81C8B0FF6BAE94FF6BAE94FFADB7B880ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF91E9D3FF75E4C8FF68E1C2FF69E1C3FF6EE2C5FF75E4C8FF80E6CCFF8EE9 + D2FF81C8B0FF6BAE94FF6BAE94FFADB7B880ADB7B880ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF95EAD4FF79E5C9FF6FE3C5FF75E4C8FF80E6CCFF8EE9D2FF81C8B0FF6BAE + 94FF6BAE94FFADB7B880ADB7B880ADB7B800ADB7B800ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFA4EDDBFF8BE8D1FF84E7CEFF8FE9D2FF81C8B0FF6BAE94FF6BAE94FFADB7 + B880ADB7B880ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF8ECAB5FFAAEEDDFF84C8B2FF6BAE94FF6BAE94FFADB7B880ADB7B880ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B8806BAE94FF6BAE94FF6BAE94FFADB7B880ADB7B880ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B880ADB7B880ADB7B880ADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B8006BAE94FF6BAE94FFADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B8006BAE94FF6BAE94FF6BAE94FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFA7CFC0FFA7CFC0FF6BAE94FF6BAE94FFADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B8006BAE94FFFCFEFEFFFCFEFEFF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFF7FCFBFFF5FBFAFFF5FBFAFFA4CEBEFF6BAE94FF6BAE94FFADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B8006BAE94FFF7FCFBFFF7FCFBFF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFEFF9F7FFECF7F5FFEAF7F4FFECF7F5FFEEF8F6FFA2CDBDFF6BAE94FF6BAE + 94FFADB7B800ADB7B800ADB7B8006BAE94FFF1F9F7FFF1F9F7FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFE7F6F2FFE1F3EFFFDFF2EDFFE0F3EEFFE1F3EFFFE3F4F0FFE6F5F2FF9FCC + BCFF6BAE94FF6BAE94FFADB7B8006BAE94FFEAF7F4FFEAF7F4FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFDFF3EEFFD7F1E9FFD3EFE7FFD3EFE7FFD4EFE7FFD5F0E8FFD7F1E9FFDAF2 + EBFFDEF3EDFF9CCBBAFF6BAE94FF6BAE94FFE3F5F0FFE3F5F0FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFD7F1EAFFCDEDE5FFC8EBE2FFC8EBE2FFC8EBE2FFC8EBE2FFC9EBE2FFCBEC + E3FFCDEDE5FFD1EEE7FFD8F1EAFF6BAE94FFDCF2EDFFDCF2EDFF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFCFEEE6FFC3EAE0FFBDE8DDFFBDE8DDFFBDE8DDFFBDE8DDFFBDE8DDFFBDE8 + DDFFBEE8DEFFC0E9DFFFC6EBE2FF6BAE94FFD6F1EAFFD6F1EAFF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF91E9D3FF75E4C8FF67E1C2FF67E1C2FF67E1C2FF67E1C2FF67E1C2FF68E1 + C2FF69E1C3FF6FE3C5FF7CE5CBFF6BAE94FFA0ECD9FFA0ECD9FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF91E9D3FF75E4C8FF67E1C2FF67E1C2FF67E1C2FF68E1C2FF69E1C3FF6EE2 + C5FF75E4C8FF80E6CCFF93EAD3FF6BAE94FFA0ECD9FFA0ECD9FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF91E9D3FF75E4C8FF67E1C2FF68E1C2FF69E1C3FF6EE2C5FF75E4C8FF80E6 + CCFF8EE9D2FF81C8B0FF6BAE94FF6BAE94FFA0ECD9FFA0ECD9FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF91E9D3FF76E4C8FF69E1C3FF6EE2C5FF75E4C8FF80E6CCFF8EE9D2FF81C8 + B0FF6BAE94FF6BAE94FFADB7B8806BAE94FFA0ECD9FFA0ECD9FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF97EAD5FF7EE6CBFF76E4C8FF80E6CCFF8EE9D2FF81C8B0FF6BAE94FF6BAE + 94FFADB7B880ADB7B880ADB7B8006BAE94FFA0ECD9FFA0ECD9FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FFA8EEDCFF93EAD4FF91E9D3FF81C8B0FF6BAE94FF6BAE94FFADB7B880ADB7 + B880ADB7B800ADB7B800ADB7B8006BAE94FFAAEEDDFFAAEEDDFF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006BAE + 94FF90CAB6FF8ACAB4FF6BAE94FF6BAE94FFADB7B880ADB7B880ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B8006BAE94FFBFF2E5FFBFF2E5FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B8806BAE94FF6BAE94FFADB7B880ADB7B880ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B8006BAE94FF6BAE94FF6BAE94FF6BAE94FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B880ADB7B880ADB7B800ADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B880ADB7B880ADB7B880ADB7B880FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00EFC7A500EFC7A500EFC7A500EFC7A500EFC7 + A500EFC7A510EFC8A6EBF1CCABFBF1CBABFBF1CBAAFBF1CCAAFBF1CBABFBF1CB + ABFBF1CBABFBF1CBAAFBF1CBAAFBF1CCABFBEFC8A7EBEFC7A610EFC7A600EFC7 + A600EFC7A600EFC7A600EFC7A600F4C9A400F4CAA400F0C8A500EEC7A500EEC7 + A500EDC5A310F2CFAEEFFDE5C8FFFBE3C7FFFCE3C6FFFBE3C6FFFBE3C7FFFBE3 + C7FFFBE3C7FFFCE3C6FFFCE3C6FFFCE4C8FFF3CFB0EFEFC7A510F0C9A800EFC9 + A800F1CAA700F6CBA700F5CBA700C6B9AE00C4B8AF00E8C5A700F5CAA500F0C9 + A600EFC7A410F2CEAEEFFBE1C3FFFADFC1FFFADFC1FFFBDFC1FFFBDFC1FFFADF + C2FFFBDFC1FFFADFC1FFFADFC1FFFBE0C2FFF4D1B0EFF0CBA910F1CCAA00F7CE + A900E9C9AC00C7BCB300C9BDB200AFB1B300AFB1B300BCBCBB00C8BBB000F3CB + A600F1CAA610F3D0ADEFFADFBFFFFADEBEFFFADDBDFFFADDBDFFFADEBEFFFADE + BEFFFADDBDFFFADEBDFFFADEBEFFFADEBFFFF5D2B1EFF4CEAC10F5CFAC00C8BC + B200BEBDBD00B3B5B700B3B5B700B2B2B200B2B2B200BCBCBC00AFB2B500C8BB + AE00F2CBA810F5D1ADEFFADDBBFFFADCBAFFFADCBAFFFADDBAFFF9DCBAFFFADD + BAFFFADCBBFFF9DBBAFFFADCBAFFFADDBAFFF8D4B1EFF8D2AE10C9BCB100AFB1 + B400BEBEBE00B6B6B600B6B6B600B2B2B200B2B2B200BCBCBC00B4B4B400AAAF + B200EBC8AE0FFBD4AEEFF9DAB7FFFADAB6FFF9D9B6FFFADAB7FFF9DBB7FFF9DB + B7FFF9DAB7FFF9DAB7FFFADAB7FFFBDAB6FFF6D5B1EFC8BDAE0DACAFB200B4B4 + B400BEBEBE00B6B6B600B6B6B600B2B2B200B2B2B200BBBCBB00B4B3B41BB5B0 + B3108CBAA010EAD2ABEDFCD9B4FFF8D9B4FFF9D9B4FFF8D9B3FFF9D9B4FFF9D9 + B4FFF8D9B3FFF9D9B3FFF9D9B4FFFBDAB4FFF1D3B0F0ADB1AE23B4B1B310B4B3 + B30DBDBEBD00B6B6B600B6B6B600B3B3B300B2B2B207CCC2C59D9CCDBDF333C0 + 95F155BA96EFEBC7A0FEFFCDA5FFFACCA4FFFACCA4FFFACCA4FFFACCA4FFFACC + A4FFFACCA4FFFACCA4FFFACCA4FFFECDA5FFEFC9A1FE5BB996F22FBA8FF1A3CB + BEEBCEC5C8A5B6B6B610B7B7B700BEBEBE00BBBBBB5AF6EDF0FEBBECDCFF31D2 + A1FF47D5A6FFA9B58AFFB8B58CFFB5B68CFFB5B68CFFB5B68CFFB5B68CFFB5B6 + 8CFFB5B68CFFB5B68DFFB5B68CFFB8B58CFFA8B78CFF32CA99FF1AC28DFFC9EF + E1FFFBF1F4FFC0C0C065C3C3C300C1C1C100BFBEBE67FBF4F6FFADE7D4FF3BCF + A1FF6AEFC8FF50D7ADFF50D5ACFF50D6ACFF50D6ACFF50D5ACFF50D5ACFF50D5 + ACFF50D6ACFF50D6ADFF50D6ACFF51D5ACFF4DD7ADFF61ECC3FF3CCB9CFFC4EA + DCFFFFF6FAFFC5C5C571C8C8C800C1C1C100BEBEBE6DFBF4F6FFB1E6D4FF3ACB + 9DFF74F4CFFF6EF1CCFF6EF2CCFF6EF1CCFF6EF1CCFF6EF2CCFF6EF2CCFF6EF2 + CCFF6EF1CCFF6EF1CCFF6EF1CCFF6EF2CCFF6FF1CCFF76F4D0FF3CC899FFC5E7 + DAFFFFF6FAFFC4C4C476C7C7C700BCBCBC00B9B9B970F9F2F5FFBCE7D7FF33C2 + 91FF38CB9CFF24C692FF26C895FF26C895FF26C895FF26C895FF26C895FF26C8 + 95FF26C895FF26C895FF26C895FF26C895FF23C592FF39CD9FFF38BF90FFC7E7 + D9FFFCF4F7FFBDBDBD76C0C0C000B6B6B600B3B3B371EFE8EBFFC0E5D7FF2BB4 + 83FF2AB281FF1BAB76FF1DAD79FF1DAD79FF1DAD79FF1DAD79FF1DAD79FF1DAD + 79FF1DAD79FF1DAD79FF1DAD79FF1DAD79FF1BAB76FF2AB281FF2CAF7FFFC9E6 + DAFFEEE7EBFFB5B5B575B8B8B800B3B3B300B0B0B074E5DEE1FFC0E2D3FF2BB2 + 7FFF47C89CFF40C092FF41C092FF41C092FF41C092FF41C092FF41C093FF41C0 + 93FF41C093FF41C093FF41C093FF41C093FF40BF92FF47C99CFF2CAE7DFFC5E2 + D4FFE2DBDEFFB0B0B076B3B3B300ADADAD00AAAAAA7FD6D2D4FFE7EEEBFF6DBF + 9DFF30A475FF3AA97BFF3AA97AFF3AA87AFF3AA87AFF3AA77AFF3AA879FF3AA8 + 79FF3AA779FF3BA77AFF3BA77AFF3BA77AFF3BA77AFF30A272FF7DC4A6FFEDEF + EEFFD1CECFFFAAAAAA7FADADAD00B7B7B700AAAAAA80CDCDCDFFE1E0E0FFEBEA + EBFFE3E8E6FFEAF0EEFFE4ECEBFFE4ECEBFFE4ECEBFFE4ECEAFFE4ECEAFFE4EC + EAFFE4ECEAFFE4EBEAFFE4EBEAFFE3EBE9FFE4ECEAFFEFF0EFFFCEE0D9FFC8D4 + CFFFCBC9CAFFAAAAAA80B7B7B70070707000B8B8B880CBCBCBFFD8D8D8FFD6D6 + D6FFCDCDCEFF969190FFB7A9A3FFB6A8A2FFB6A8A2FFB6A8A2FFB5A8A1FFB5A8 + A2FFB5A8A2FFB5A7A1FFB5A7A2FFB5A8A2FFAC9F9AFF9E989AFF9CC1B1FFAEC6 + BCFFCBC7C9FFB8B8B88070707000000000006E6E6E82D4D4D4FFD4D4D4FFD5D5 + D5FFBEC0C2FF554B43FFBA9472FFB69373FFB69375FFB69577FFB6977BFFB698 + 7CFFB6987EFFB79A80FFB79A85FFBA9F89FFA38B77FF585756FFD8D4D7FFD2D0 + D1FFD0D0D0FF6E6E6E8200000000000000073F3F3F46B4B4B4E0D3D3D3FFD7D7 + D7FFBBBEC0FF6D6257FFEFBF91FFEABC91FFEABD94FFEABE96FFEAC19AFFEAC3 + 9FFFEAC5A2FFEAC6A5FFEAC8AAFFEDCEB0FFD5B99FFF6A6866FFD5D6D7FFD2D2 + D2FFB8B8B8E9444444520000000500000019000000253E3E3E51777777B37575 + 75B684878AB99A8E82D1FFD4A4FFFFD0A3FFFFD1A4FFFFD1A7FFFFD4A9FFFFD5 + AEFFFFD8B1FFFFD9B3FFFFDAB6FFFFDFBCFFF7D6B8FB787674C2747575B47979 + 79B4434343570000002400000019000000040000000500000000000000000000 + 000010121200675D5243FFF0C4FFFFE6BCFFFFE6BCFFFFE6BDFFFFE7BEFFFFE8 + BFFFFFEAC3FFFFEAC3FFFFEBC5FFFFEFCAFFFFE3C1FE2725230C000000000000 + 0000000000000000000500000004000000000000000000000000000000000000 + 00000000000F0503022C2B2620542B241E5A2B241E592B241E592B241E592B25 + 1E592B251F592B251F592B251F592B26205A27221D4F00000022000000090000 + 0000000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B8004646C1FF4646C1FFADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B8004646C1FF4646C1FFADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B8004646C1FF9191DBFF9191DBFF4646C1FFADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B8004646C1FF9191DBFF9191DBFF4646C1FFADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF004646 + C1FF8F8FDBFFF3F3FFFFF2F2FFFF8E8EDBFF4646C1FFADB7B800ADB7B800ADB7 + B800ADB7B8004646C1FF8E8EDBFFF2F2FFFFF3F3FFFF8F8FDBFF4646C1FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF004646 + C1FF8C8CDBFFE9E9FFFFE6E6FFFFE7E7FFFF8A8ADBFF4646C1FFADB7B800ADB7 + B8004646C1FF8A8ADBFFE7E7FFFFE6E6FFFFE9E9FFFF8C8CDBFF4646C1FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B8804646C1FF8787DBFFDCDCFFFFD9D9FFFFDBDBFFFF8585DBFF4646C1FF4646 + C1FF8585DBFFDBDBFFFFD9D9FFFFDCDCFFFF8787DBFF4646C1FFADB7B880FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B8804646C1FF8383DBFFCFCFFFFFCBCBFFFFCBCBFFFFCCCCFFFFCCCC + FFFFCBCBFFFFCBCBFFFFCFCFFFFF8383DBFF4646C1FFADB7B880ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B8804646C1FF7C7CDBFFBFBFFFFFB9B9FFFFB8B8FFFFB8B8 + FFFFB9B9FFFFBFBFFFFF7C7CDBFF4646C1FFADB7B880ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B800ADB7B8804646C1FFB5B5FFFFABABFFFFA8A8FFFFA8A8 + FFFFABABFFFFB5B5FFFF4646C1FFADB7B880ADB7B800ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B800ADB7B8004646C1FF7272FFFF5F5FFFFF5858FFFF5858 + FFFF5F5FFFFF7272FFFF4646C1FFADB7B800ADB7B800ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B8004646C1FF6161DBFF6E6EFFFF6262FFFF5F5FFFFF5F5F + FFFF6262FFFF6E6EFFFF6161DBFF4646C1FFADB7B800ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B8004646C1FF6767DBFF7B7BFFFF7070FFFF6E6EFFFF7272FFFF7272 + FFFF6E6EFFFF7070FFFF7B7BFFFF6767DBFF4646C1FFADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B8004646C1FF6A6ADBFF8080FFFF7575FFFF7B7BFFFF6161DBFF4646C1FF4646 + C1FF6161DBFF7B7BFFFF7575FFFF8080FFFF6A6ADBFF4646C1FFADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF004646 + C1FF7474DBFF8E8EFFFF7A7AFFFF8080FFFF6767DBFF4646C1FFADB7B880ADB7 + B8804646C1FF6767DBFF8080FFFF7A7AFFFF8E8EFFFF7474DBFF4646C1FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF004646 + C1FF7575DBFF9898FFFF8E8EFFFF6A6ADBFF4646C1FFADB7B880ADB7B800ADB7 + B800ADB7B8804646C1FF6A6ADBFF8E8EFFFF9898FFFF7575DBFF4646C1FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B8804646C1FF7575DBFF7474DBFF4646C1FFADB7B880ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B8804646C1FF7474DBFF7575DBFF4646C1FFADB7B880FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B8804646C1FF4646C1FFADB7B880ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B8804646C1FF4646C1FFADB7B880ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADB7 + B800ADB7B800ADB7B880ADB7B880ADB7B800ADB7B800ADB7B800ADB7B800ADB7 + B800ADB7B800ADB7B800ADB7B800ADB7B880ADB7B880ADB7B800ADB7B800FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00 + } + end + object ALMain: TActionList + Images = ILMain + left = 56 + top = 54 + object ACPageFirst: TAction + Hint = 'First page' + ImageIndex = 0 + OnExecute = ACPageFirstExecute + OnUpdate = ACPageFirstUpdate + end + object ACPagePrevious: TAction + Caption = 'Previous page' + Hint = 'Previous page' + ImageIndex = 1 + OnExecute = ACPagePreviousExecute + OnUpdate = ACPageFirstUpdate + end + object ACPageNext: TAction + Caption = 'Next page' + Hint = 'Next page' + ImageIndex = 2 + OnExecute = ACPageNextExecute + OnUpdate = ACPageNextUpdate + end + object ACPageLast: TAction + Caption = 'Last page' + Hint = 'Last page' + ImageIndex = 3 + OnExecute = ACPageLastExecute + OnUpdate = ACPageNextUpdate + end + object ACPrint: TAction + Caption = 'Print' + Hint = 'Print' + ImageIndex = 4 + OnExecute = ACPrintExecute + OnUpdate = ACPrintUpdate + end + object ACClose: TAction + Caption = 'Close' + Hint = 'Close preview' + ImageIndex = 5 + OnExecute = ACCloseExecute + OnUpdate = ACCloseUpdate + end + end + object ILMainDis: TImageList + Height = 24 + Width = 24 + left = 96 + top = 54 + Bitmap = { + 4C69060000001800000018000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFF8C8C8CFF8C8C8CFF8C8C8CFFB2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B2008C8C8CFF8C8C8CFFB2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFFDFDFDFFFDFDFDFF8C8C8CFFB2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B2008C8C8CFF8C8C8CFFBBBBBBFFBBBBBBFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFF9F9F9FFF9F9F9FF8C8C8CFFB2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B2008C8C8CFF8C8C8CFFB9B9B9FFF8F8F8FFF8F8F8FFF9F9F9FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFF5F5F5FFF5F5F5FF8C8C8CFFB2B2B200B2B2B200B2B2B2008C8C8CFF8C8C + 8CFFB7B7B7FFF3F3F3FFF1F1F1FFF0F0F0FFF1F1F1FFF4F4F4FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFF0F0F0FFF0F0F0FF8C8C8CFFB2B2B2008C8C8CFF8C8C8CFFB5B5B5FFEDED + EDFFEBEBEBFFEAEAEAFFE9E9E9FFE8E8E8FFEAEAEAFFEEEEEEFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFECECECFFECECECFF8C8C8CFF8C8C8CFFB3B3B3FFE8E8E8FFE6E6E6FFE4E4 + E4FFE2E2E2FFE1E1E1FFE1E1E1FFE1E1E1FFE4E4E4FFE9E9E9FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFE7E7E7FFE7E7E7FF8C8C8CFFE4E4E4FFDFDFDFFFDDDDDDFFDBDBDBFFDADA + DAFFD9D9D9FFD9D9D9FFD9D9D9FFD9D9D9FFDDDDDDFFE4E4E4FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFE3E3E3FFE3E3E3FF8C8C8CFFD8D8D8FFD4D4D4FFD3D3D3FFD2D2D2FFD2D2 + D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD6D6D6FFDEDEDEFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFC6C6C6FFC6C6C6FF8C8C8CFFB0B0B0FFA9A9A9FFA5A5A5FFA4A4A4FFA4A4 + A4FFA4A4A4FFA4A4A4FFA4A4A4FFA4A4A4FFACACACFFBDBDBDFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFC6C6C6FFC6C6C6FF8C8C8CFFBEBEBEFFB3B3B3FFACACACFFA8A8A8FFA5A5 + A5FFA4A4A4FFA4A4A4FFA4A4A4FFA4A4A4FFACACACFFBDBDBDFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFC6C6C6FFC6C6C6FF8C8C8CFF8C8C8CFFA4A4A4FFBBBBBBFFB3B3B3FFACAC + ACFFA8A8A8FFA5A5A5FFA4A4A4FFA4A4A4FFACACACFFBDBDBDFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFC6C6C6FFC6C6C6FF8C8C8CFFB2B2B2808C8C8CFF8C8C8CFFA4A4A4FFBBBB + BBFFB3B3B3FFACACACFFA8A8A8FFA5A5A5FFADADADFFBDBDBDFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFC6C6C6FFC6C6C6FF8C8C8CFFB2B2B200B2B2B280B2B2B2808C8C8CFF8C8C + 8CFFA4A4A4FFBBBBBBFFB3B3B3FFADADADFFB2B2B2FFC0C0C0FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFCCCCCCFFCCCCCCFF8C8C8CFFB2B2B200B2B2B200B2B2B200B2B2B280B2B2 + B2808C8C8CFF8C8C8CFFA4A4A4FFBDBDBDFFBEBEBEFFCBCBCBFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFD8D8D8FFD8D8D8FF8C8C8CFFB2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B280B2B2B2808C8C8CFF8C8C8CFFAAAAAAFFADADADFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFF8C8C8CFF8C8C8CFF8C8C8CFFB2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B280B2B2B2808C8C8CFF8C8C8CFFB2B2B280FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B280B2B2B280B2B2B280B2B2B280B2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B280B2B2B280B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B2008C8C8CFF8C8C8CFF8C8C8CFFB2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B2008C8C8CFF8C8C8CFFBBBBBBFFFDFDFDFFBBBBBBFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B2008C8C + 8CFF8C8C8CFFB9B9B9FFF8F8F8FFF7F7F7FFF7F7F7FFF9F9F9FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B2008C8C8CFF8C8C8CFFB7B7 + B7FFF3F3F3FFF1F1F1FFF0F0F0FFEFEFEFFFF1F1F1FFF4F4F4FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B200B2B2B2008C8C8CFF8C8C8CFFB5B5B5FFEDEDEDFFEBEB + EBFFEAEAEAFFE9E9E9FFE8E8E8FFE8E8E8FFEAEAEAFFEEEEEEFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B2008C8C8CFF8C8C8CFFB3B3B3FFE8E8E8FFE6E6E6FFE4E4E4FFE2E2 + E2FFE1E1E1FFE1E1E1FFE1E1E1FFE1E1E1FFE4E4E4FFE9E9E9FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B2008C8C8CFFB3B3B3FFE4E4E4FFDFDFDFFFDDDDDDFFDBDBDBFFDADADAFFD9D9 + D9FFD9D9D9FFD9D9D9FFD9D9D9FFD9D9D9FFDDDDDDFFE4E4E4FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFB3B3B3FFE0E0E0FFD8D8D8FFD4D4D4FFD3D3D3FFD2D2D2FFD2D2D2FFD2D2 + D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD6D6D6FFDEDEDEFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFABABABFFC0C0C0FFB0B0B0FFA9A9A9FFA5A5A5FFA4A4A4FFA4A4A4FFA4A4 + A4FFA4A4A4FFA4A4A4FFA4A4A4FFA4A4A4FFACACACFFBDBDBDFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B2808C8C8CFFA8A8A8FFBEBEBEFFB3B3B3FFACACACFFA8A8A8FFA5A5A5FFA4A4 + A4FFA4A4A4FFA4A4A4FFA4A4A4FFA4A4A4FFACACACFFBDBDBDFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B2808C8C8CFF8C8C8CFFA4A4A4FFBBBBBBFFB3B3B3FFACACACFFA8A8 + A8FFA5A5A5FFA4A4A4FFA4A4A4FFA4A4A4FFACACACFFBDBDBDFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B280B2B2B2808C8C8CFF8C8C8CFFA4A4A4FFBBBBBBFFB3B3 + B3FFACACACFFA8A8A8FFA5A5A5FFA4A4A4FFACACACFFBDBDBDFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B280B2B2B2808C8C8CFF8C8C8CFFA4A4 + A4FFBBBBBBFFB3B3B3FFACACACFFA9A9A9FFAFAFAFFFBFBFBFFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B280B2B2B2808C8C + 8CFF8C8C8CFFA4A4A4FFBCBCBCFFB5B5B5FFB9B9B9FFC8C8C8FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B280B2B2B2808C8C8CFF8C8C8CFFA6A6A6FFCCCCCCFFACACACFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B280B2B2B2808C8C8CFF8C8C8CFF8C8C8CFFB2B2B280FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B280B2B2B280B2B2B280B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B2008C8C8CFF8C8C8CFF8C8C8CFFB2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFBBBBBBFFFDFDFDFFBBBBBBFF8C8C8CFF8C8C8CFFB2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFF9F9F9FFF7F7F7FFF7F7F7FFF8F8F8FFB9B9B9FF8C8C8CFF8C8C8CFFB2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFF4F4F4FFF1F1F1FFEFEFEFFFF0F0F0FFF1F1F1FFF3F3F3FFB7B7B7FF8C8C + 8CFF8C8C8CFFB2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFEEEEEEFFEAEAEAFFE8E8E8FFE8E8E8FFE9E9E9FFEAEAEAFFEBEBEBFFEDED + EDFFB5B5B5FF8C8C8CFF8C8C8CFFB2B2B200B2B2B200B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFE9E9E9FFE4E4E4FFE1E1E1FFE1E1E1FFE1E1E1FFE1E1E1FFE2E2E2FFE4E4 + E4FFE6E6E6FFE8E8E8FFB3B3B3FF8C8C8CFF8C8C8CFFB2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFE4E4E4FFDDDDDDFFD9D9D9FFD9D9D9FFD9D9D9FFD9D9D9FFD9D9D9FFDADA + DAFFDBDBDBFFDDDDDDFFDFDFDFFFE4E4E4FFB3B3B3FF8C8C8CFFB2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFDEDEDEFFD6D6D6FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2 + D2FFD2D2D2FFD3D3D3FFD4D4D4FFD8D8D8FFE0E0E0FFB3B3B3FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFBDBDBDFFACACACFFA4A4A4FFA4A4A4FFA4A4A4FFA4A4A4FFA4A4A4FFA4A4 + A4FFA4A4A4FFA5A5A5FFA9A9A9FFB0B0B0FFC0C0C0FFABABABFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFBDBDBDFFACACACFFA4A4A4FFA4A4A4FFA4A4A4FFA4A4A4FFA4A4A4FFA5A5 + A5FFA8A8A8FFACACACFFB3B3B3FFBEBEBEFFA8A8A8FF8C8C8CFFB2B2B280FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFBDBDBDFFACACACFFA4A4A4FFA4A4A4FFA4A4A4FFA5A5A5FFA8A8A8FFACAC + ACFFB3B3B3FFBBBBBBFFA4A4A4FF8C8C8CFF8C8C8CFFB2B2B280B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFBDBDBDFFACACACFFA4A4A4FFA5A5A5FFA8A8A8FFACACACFFB3B3B3FFBBBB + BBFFA4A4A4FF8C8C8CFF8C8C8CFFB2B2B280B2B2B280B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFBFBFBFFFAFAFAFFFA9A9A9FFACACACFFB3B3B3FFBBBBBBFFA4A4A4FF8C8C + 8CFF8C8C8CFFB2B2B280B2B2B280B2B2B200B2B2B200B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFC8C8C8FFB9B9B9FFB5B5B5FFBCBCBCFFA4A4A4FF8C8C8CFF8C8C8CFFB2B2 + B280B2B2B280B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFACACACFFCCCCCCFFA6A6A6FF8C8C8CFF8C8C8CFFB2B2B280B2B2B280B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B2808C8C8CFF8C8C8CFF8C8C8CFFB2B2B280B2B2B280B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B280B2B2B280B2B2B280B2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B2008C8C8CFF8C8C8CFFB2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B2008C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFBBBBBBFFBBBBBBFF8C8C8CFF8C8C8CFFB2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B2008C8C8CFFFDFDFDFFFDFDFDFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFF9F9F9FFF8F8F8FFF8F8F8FFB9B9B9FF8C8C8CFF8C8C8CFFB2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B2008C8C8CFFF9F9F9FFF9F9F9FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFF4F4F4FFF1F1F1FFF0F0F0FFF1F1F1FFF3F3F3FFB7B7B7FF8C8C8CFF8C8C + 8CFFB2B2B200B2B2B200B2B2B2008C8C8CFFF5F5F5FFF5F5F5FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFEEEEEEFFEAEAEAFFE8E8E8FFE9E9E9FFEAEAEAFFEBEBEBFFEDEDEDFFB5B5 + B5FF8C8C8CFF8C8C8CFFB2B2B2008C8C8CFFF0F0F0FFF0F0F0FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFE9E9E9FFE4E4E4FFE1E1E1FFE1E1E1FFE1E1E1FFE2E2E2FFE4E4E4FFE6E6 + E6FFE8E8E8FFB3B3B3FF8C8C8CFF8C8C8CFFECECECFFECECECFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFE4E4E4FFDDDDDDFFD9D9D9FFD9D9D9FFD9D9D9FFD9D9D9FFDADADAFFDBDB + DBFFDDDDDDFFDFDFDFFFE4E4E4FF8C8C8CFFE7E7E7FFE7E7E7FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFDEDEDEFFD6D6D6FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2 + D2FFD3D3D3FFD4D4D4FFD8D8D8FF8C8C8CFFE3E3E3FFE3E3E3FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFBDBDBDFFACACACFFA4A4A4FFA4A4A4FFA4A4A4FFA4A4A4FFA4A4A4FFA4A4 + A4FFA5A5A5FFA9A9A9FFB0B0B0FF8C8C8CFFC6C6C6FFC6C6C6FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFBDBDBDFFACACACFFA4A4A4FFA4A4A4FFA4A4A4FFA4A4A4FFA5A5A5FFA8A8 + A8FFACACACFFB3B3B3FFBEBEBEFF8C8C8CFFC6C6C6FFC6C6C6FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFBDBDBDFFACACACFFA4A4A4FFA4A4A4FFA5A5A5FFA8A8A8FFACACACFFB3B3 + B3FFBBBBBBFFA4A4A4FF8C8C8CFF8C8C8CFFC6C6C6FFC6C6C6FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFBDBDBDFFADADADFFA5A5A5FFA8A8A8FFACACACFFB3B3B3FFBBBBBBFFA4A4 + A4FF8C8C8CFF8C8C8CFFB2B2B2808C8C8CFFC6C6C6FFC6C6C6FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFC0C0C0FFB2B2B2FFADADADFFB3B3B3FFBBBBBBFFA4A4A4FF8C8C8CFF8C8C + 8CFFB2B2B280B2B2B280B2B2B2008C8C8CFFC6C6C6FFC6C6C6FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFCBCBCBFFBEBEBEFFBDBDBDFFA4A4A4FF8C8C8CFF8C8C8CFFB2B2B280B2B2 + B280B2B2B200B2B2B200B2B2B2008C8C8CFFCCCCCCFFCCCCCCFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C8C + 8CFFADADADFFAAAAAAFF8C8C8CFF8C8C8CFFB2B2B280B2B2B280B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B2008C8C8CFFD8D8D8FFD8D8D8FF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B2808C8C8CFF8C8C8CFFB2B2B280B2B2B280B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B2008C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B280B2B2B280B2B2B200B2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B280B2B2B280B2B2B280B2B2B280FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00CACACA00CACACA00CACACA00CACACA00CACA + CA00CACACA10CACACAEBCECECEFBCECECEFBCDCDCDFBCDCDCDFBCECECEFBCECE + CEFBCECECEFBCDCDCDFBCDCDCDFBCECECEFBCBCBCBEBCACACA10CACACA00CACA + CA00CACACA00CACACA00CACACA00CCCCCC00CCCCCC00CACACA00C9C9C900C9C9 + C900C8C8C810D0D0D0EFE2E2E2FFE1E1E1FFE1E1E1FFE0E0E0FFE1E1E1FFE1E1 + E1FFE1E1E1FFE1E1E1FFE1E1E1FFE2E2E2FFD1D1D1EFCACACA10CCCCCC00CBCB + CB00CCCCCC00CECECE00CECECE00BABABA00B9B9B900C7C7C700CDCDCD00CBCB + CB00C9C9C910D0D0D0EFDFDFDFFFDDDDDDFFDDDDDDFFDEDEDEFFDEDEDEFFDEDE + DEFFDEDEDEFFDDDDDDFFDDDDDDFFDEDEDEFFD2D2D2EFCCCCCC10CDCDCD00D0D0 + D000CACACA00BDBDBD00BDBDBD00B1B1B100B1B1B100BBBBBB00BCBCBC00CCCC + CC00CBCBCB10D0D0D0EFDCDCDCFFDCDCDCFFDBDBDBFFDBDBDBFFDCDCDCFFDCDC + DCFFDBDBDBFFDBDBDBFFDCDCDCFFDCDCDCFFD3D3D3EFD0D0D010D0D0D000BDBD + BD00BDBDBD00B5B5B500B5B5B500B2B2B200B2B2B200BCBCBC00B2B2B200BBBB + BB00CDCDCD10D1D1D1EFDADADAFFDADADAFFDADADAFFDADADAFFD9D9D9FFDADA + DAFFDADADAFFD9D9D9FFDADADAFFDADADAFFD4D4D4EFD3D3D310BDBDBD00B1B1 + B100BEBEBE00B6B6B600B6B6B600B2B2B200B2B2B200BCBCBC00B4B4B400AEAE + AE00CCCCCC0FD4D4D4EFD8D8D8FFD8D8D8FFD7D7D7FFD8D8D8FFD8D8D8FFD8D8 + D8FFD8D8D8FFD8D8D8FFD8D8D8FFD8D8D8FFD3D3D3EFBBBBBB0DAFAFAF00B4B4 + B400BEBEBE00B6B6B600B6B6B600B2B2B200B2B2B200BBBBBB00B3B3B31BB2B2 + B210A3A3A310CACACAEDD8D8D8FFD6D6D6FFD6D6D6FFD5D5D5FFD6D6D6FFD6D6 + D6FFD5D5D5FFD6D6D6FFD6D6D6FFD7D7D7FFD0D0D0F0AFAFAF23B2B2B210B3B3 + B30DBDBDBD00B6B6B600B6B6B600B3B3B300B2B2B207C7C7C79DB4B4B4F37979 + 79F1878787EFC5C5C5FED2D2D2FFCFCFCFFFCFCFCFFFCFCFCFFFCFCFCFFFCFCF + CFFFCFCFCFFFCFCFCFFFCFCFCFFFD1D1D1FFC8C8C8FE8A8A8AF2747474F1B7B7 + B7EBC9C9C9A5B6B6B610B7B7B700BEBEBE00BBBBBB5AF1F1F1FED3D3D3FF8181 + 81FF8E8E8EFF9F9F9FFFA2A2A2FFA1A1A1FFA1A1A1FFA1A1A1FFA1A1A1FFA1A1 + A1FFA1A1A1FFA1A1A1FFA1A1A1FFA2A2A2FFA1A1A1FF7E7E7EFF6E6E6EFFDCDC + DCFFF6F6F6FFC0C0C065C3C3C300C1C1C100BEBEBE67F7F7F7FFCACACAFF8585 + 85FFACACACFF939393FF929292FF939393FF939393FF929292FF929292FF9292 + 92FF939393FF939393FF939393FF939393FF929292FFA6A6A6FF838383FFD7D7 + D7FFFAFAFAFFC5C5C571C8C8C800C1C1C100BEBEBE6DF7F7F7FFCBCBCBFF8282 + 82FFB4B4B4FFAFAFAFFFB0B0B0FFAFAFAFFFAFAFAFFFB0B0B0FFB0B0B0FFB0B0 + B0FFAFAFAFFFAFAFAFFFAFAFAFFFB0B0B0FFB0B0B0FFB5B5B5FF828282FFD6D6 + D6FFFAFAFAFFC4C4C476C7C7C700BCBCBC00B9B9B970F5F5F5FFD1D1D1FF7A7A + 7AFF818181FF757575FF777777FF777777FF777777FF777777FF777777FF7777 + 77FF777777FF777777FF777777FF777777FF747474FF838383FF7B7B7BFFD7D7 + D7FFF8F8F8FFBDBDBD76C0C0C000B6B6B600B3B3B371EBEBEBFFD2D2D2FF6F6F + 6FFF6E6E6EFF636363FF656565FF656565FF656565FF656565FF656565FF6565 + 65FF656565FF656565FF656565FF656565FF636363FF6E6E6EFF6D6D6DFFD7D7 + D7FFEAEAEAFFB5B5B575B8B8B800B3B3B300B0B0B074E1E1E1FFD1D1D1FF6E6E + 6EFF878787FF808080FF808080FF808080FF808080FF808080FF808080FF8080 + 80FF808080FF808080FF808080FF808080FF7F7F7FFF888888FF6D6D6DFFD3D3 + D3FFDEDEDEFFB0B0B076B3B3B300ADADAD00AAAAAA7FD4D4D4FFEAEAEAFF9696 + 96FF6A6A6AFF717171FF717171FF717171FF717171FF707070FF717171FF7171 + 71FF707070FF717171FF717171FF717171FF717171FF696969FFA0A0A0FFEEEE + EEFFCFCFCFFFAAAAAA7FADADAD00B7B7B700AAAAAA80CDCDCDFFE0E0E0FFEAEA + EAFFE5E5E5FFEDEDEDFFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8 + E8FFE8E8E8FFE7E7E7FFE7E7E7FFE7E7E7FFE8E8E8FFEFEFEFFFD7D7D7FFCECE + CEFFCACACAFFAAAAAA80B7B7B70070707000B8B8B880CBCBCBFFD8D8D8FFD6D6 + D6FFCDCDCDFF939393FFADADADFFACACACFFACACACFFACACACFFABABABFFABAB + ABFFABABABFFABABABFFABABABFFABABABFFA3A3A3FF9B9B9BFFAEAEAEFFBABA + BAFFC9C9C9FFB8B8B88070707000000000006E6E6E82D4D4D4FFD4D4D4FFD5D5 + D5FFC0C0C0FF4C4C4CFF969696FF949494FF959595FF969696FF989898FF9999 + 99FF9A9A9AFF9B9B9BFF9E9E9EFFA1A1A1FF8D8D8DFF575757FFD6D6D6FFD1D1 + D1FFD0D0D0FF6E6E6E8200000000000000073F3F3F46B4B4B4E0D3D3D3FFD7D7 + D7FFBDBDBDFF626262FFC0C0C0FFBDBDBDFFBFBFBFFFC0C0C0FFC2C2C2FFC4C4 + C4FFC6C6C6FFC7C7C7FFCACACAFFCECECEFFBABABAFF686868FFD6D6D6FFD2D2 + D2FFB8B8B8E9444444520000000500000019000000253E3E3E51777777B37575 + 75B6878787B98E8E8ED1D1D1D1FFD1D1D1FFD1D1D1FFD3D3D3FFD4D4D4FFD6D6 + D6FFD8D8D8FFD9D9D9FFDADADAFFDDDDDDFFD7D7D7FB767676C2747474B47979 + 79B4434343570000002400000019000000040000000500000000000000000000 + 0000111111005C5C5C43E1E1E1FFDDDDDDFFDDDDDDFFDEDEDEFFDEDEDEFFDFDF + DFFFE1E1E1FFE1E1E1FFE2E2E2FFE4E4E4FFE0E0E0FE2525250C000000000000 + 0000000000000000000500000004000000000000000000000000000000000000 + 00000000000F0303032C252525542424245A2424245924242459242424592424 + 24592525255925252559252525592525255A2222224F00000022000000090000 + 0000000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200838383FF838383FFB2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B200838383FF838383FFB2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200838383FFB6B6B6FFB6B6B6FF838383FFB2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200838383FFB6B6B6FFB6B6B6FF838383FFB2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008383 + 83FFB5B5B5FFF9F9F9FFF8F8F8FFB4B4B4FF838383FFB2B2B200B2B2B200B2B2 + B200B2B2B200838383FFB4B4B4FFF8F8F8FFF9F9F9FFB5B5B5FF838383FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008383 + 83FFB3B3B3FFF4F4F4FFF2F2F2FFF3F3F3FFB2B2B2FF838383FFB2B2B200B2B2 + B200838383FFB2B2B2FFF3F3F3FFF2F2F2FFF4F4F4FFB3B3B3FF838383FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B280838383FFB1B1B1FFEDEDEDFFECECECFFEDEDEDFFB0B0B0FF838383FF8383 + 83FFB0B0B0FFEDEDEDFFECECECFFEDEDEDFFB1B1B1FF838383FFB2B2B280FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B280838383FFAFAFAFFFE7E7E7FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5 + E5FFE5E5E5FFE5E5E5FFE7E7E7FFAFAFAFFF838383FFB2B2B280B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B280838383FFABABABFFDFDFDFFFDCDCDCFFDBDBDBFFDBDB + DBFFDCDCDCFFDFDFDFFFABABABFF838383FFB2B2B280B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B200B2B2B280838383FFDADADAFFD5D5D5FFD3D3D3FFD3D3 + D3FFD5D5D5FFDADADAFF838383FFB2B2B280B2B2B200B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B200B2B2B200838383FFB8B8B8FFAFAFAFFFABABABFFABAB + ABFFAFAFAFFFB8B8B8FF838383FFB2B2B200B2B2B200B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B200838383FF9E9E9EFFB6B6B6FFB0B0B0FFAFAFAFFFAFAF + AFFFB0B0B0FFB6B6B6FF9E9E9EFF838383FFB2B2B200B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200838383FFA1A1A1FFBDBDBDFFB7B7B7FFB6B6B6FFB8B8B8FFB8B8 + B8FFB6B6B6FFB7B7B7FFBDBDBDFFA1A1A1FF838383FFB2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200838383FFA2A2A2FFBFBFBFFFBABABAFFBDBDBDFF9E9E9EFF838383FF8383 + 83FF9E9E9EFFBDBDBDFFBABABAFFBFBFBFFFA2A2A2FF838383FFB2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008383 + 83FFA7A7A7FFC6C6C6FFBCBCBCFFBFBFBFFFA1A1A1FF838383FFB2B2B280B2B2 + B280838383FFA1A1A1FFBFBFBFFFBCBCBCFFC6C6C6FFA7A7A7FF838383FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008383 + 83FFA8A8A8FFCBCBCBFFC6C6C6FFA2A2A2FF838383FFB2B2B280B2B2B200B2B2 + B200B2B2B280838383FFA2A2A2FFC6C6C6FFCBCBCBFFA8A8A8FF838383FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B280838383FFA8A8A8FFA7A7A7FF838383FFB2B2B280B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B280838383FFA7A7A7FFA8A8A8FF838383FFB2B2B280FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B280838383FF838383FFB2B2B280B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B280838383FF838383FFB2B2B280B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2 + B200B2B2B200B2B2B280B2B2B280B2B2B200B2B2B200B2B2B200B2B2B200B2B2 + B200B2B2B200B2B2B200B2B2B200B2B2B280B2B2B280B2B2B200B2B2B200FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00 + } + end +end diff --git a/components/kcontrols/source/kprintpreview.lrs b/components/kcontrols/source/kprintpreview.lrs new file mode 100755 index 000000000..dc5ac2d11 --- /dev/null +++ b/components/kcontrols/source/kprintpreview.lrs @@ -0,0 +1,1447 @@ +{ This is an automatically generated lazarus resource file } + +LazarusResources.Add('TKPrintPreviewForm','FORMDATA',[ + 'TPF0'#18'TKPrintPreviewForm'#17'KPrintPreviewForm'#4'Left'#3'X'#4#6'Height'#3 + +#148#2#3'Top'#3#220#1#5'Width'#3' '#3#13'ActiveControl'#7#7'Preview'#7'Capti' + +'on'#6#13'Print Preview'#12'ClientHeight'#3#148#2#11'ClientWidth'#3' '#3#11 + +'Font.Height'#2#245#9'Font.Name'#6#6'Tahoma'#9'Icon.Data'#10#130#4#0#0'~'#4#0 + +#0#0#0#1#0#1#0#16#16#0#0#1#0' '#0'h'#4#0#0#22#0#0#0'('#0#0#0#16#0#0#0' '#0#0 + +#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#0#0#0'%'#22#19 + +#16#198#15#12#10#184#12#12#12#143#21#20#20#152#21#20#20#152#21#20#20#152#21 + +#20#20#152#21#20#20#152#21#20#20#152#21#20#20#152#21#20#20#152#12#12#12#143#0 + +#0#0')'#0#0#0#0#0#0#0#0#21#18#15#194#149#136'{'#255#143#131'x'#255#185#176 + +#168#255#241#240#238#255#241#240#238#255#241#240#238#255#241#240#238#255#241 + +#240#238#255#241#240#238#255#241#240#238#255#241#240#238#255#234#232#230#255 + +'QPO'#234#0#0#0#12#0#0#0#0#12#10#8#174#134'{p'#255#210#204#198#255#183#173 + +#163#255#193#188#182#255#227#227#227#255#224#224#224#255#223#223#223#255#254 + +#254#254#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255 + +#165#163#161#255#0#0#0'5'#0#0#0#0#0#0#0#9#19#17#15#187#165#156#147#255#225 + +#221#217#255#182#172#162#255#186#180#175#255#166#158#151#255#162#151#140#255 + +#161#150#139#255#169#162#155#255#209#208#206#255#241#241#241#255#254#254#254 + +#255#168#167#165#255#0#0#0'6'#0#0#0#0#0#0#0#0#0#0#0'6'#139#133#128#255#186 + +#176#166#255#212#206#199#255#154#141'~'#255#170#158#137#255#200#192#176#255 + +#204#195#179#255#188#174#149#255#151#139'|'#255#226#222#219#255#253#253#253 + +#255#169#168#167#255#0#0#0'6'#0#0#0#0#0#0#0#0#0#0#0'6'#170#169#168#255#224 + +#220#216#255#162#149#134#255#169#152'l'#255#198#186#145#255#208#199#169#255 + +#209#201#170#255#197#185#144#255#170#152'l'#255#164#153#140#255#247#246#245 + +#255#170#169#168#255#0#0#0'6'#0#0#0#0#0#0#0#0#0#0#0'6'#171#170#169#255#214 + +#209#204#255#160#144'n'#255#173#156'`'#255#185#172'x'#255#191#180#133#255#187 + +#176#130#255#186#174'y'#255#171#154'^'#255#169#152't'#255#217#212#208#255#171 + +#170#169#255#0#0#0'6'#0#0#0#0#0#0#0#0#0#0#0'6'#172#171#169#255#209#203#196 + +#255#161#141'Z'#255#183#164'\'#255#184#168'f'#255#184#168'i'#255#185#169'i' + +#255#187#169'c'#255#182#161'T'#255#167#146']'#255#212#206#200#255#171#169#168 + +#255#0#0#0'6'#0#0#0#0#0#0#0#0#0#0#0'6'#172#171#170#255#218#213#208#255#171 + +#154'n'#255#199#183'x'#255#202#187#128#255#203#189#133#255#201#186#127#255 + +#196#179'q'#255#180#161'W'#255#168#148'b'#255#219#213#209#255#167#165#163#255 + +#0#0#0'6'#0#0#0#0#0#0#0#0#0#0#0'6'#173#172#171#255#235#233#230#255#180#168 + +#146#255#197#185#144#255#215#205#168#255#217#208#170#255#216#207#170#255#216 + +#206#168#255#194#181#140#255#186#175#154#255#228#224#220#255#156#152#148#255 + +#0#0#0'6'#0#0#0#0#0#0#0#0#0#0#0'6'#173#172#171#255#241#239#237#255#207#203 + +#200#255#185#172#145#255#211#200#167#255#242#238#225#255#242#238#224#255#210 + +#198#164#255#186#173#147#255#201#196#191#255#213#206#199#255#129'yq'#255#0#0 + +#0'6'#0#0#0#0#0#0#0#0#0#0#0'6'#173#173#172#255#237#235#233#255#185#183#181 + +#255#195#193#190#255#184#177#168#255#165#155#134#255#168#157#135#255#204#197 + +#187#255#223#217#212#255#229#225#221#255#228#224#220#255'QNK'#236#0#0#0#27#0 + +#0#0#0#0#0#0#0#0#0#0'6'#174#173#172#255#234#231#228#255#151#150#148#255#182 + +#180#177#255#172#170#167#255#168#166#164#255#162#160#158#255#218#213#207#255 + +#232#229#226#255#230#227#224#255'eed'#236#0#0#0'1'#0#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#0'5'#173#172#171#255#230#227#223#255#230#227#223#255#230#227#223#255#230 + +#227#223#255#228#225#221#255#222#217#212#255#211#204#196#255#235#233#231#255 + +'ddd'#235#0#0#0'.'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#12'[[['#234#239#238 + +#236#255#240#238#236#255#240#238#235#255#238#235#233#255#231#227#223#255#212 + +#205#198#255#189#179#168#255'ddd'#235#0#0#0'/'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0')'#14#14#14#143#23#23#23#152#23#23#23#152#23#23#23 + +#152#22#21#21#152#19#18#17#152#12#11#10#152#0#0#0'.'#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#10'KeyP' + +'review'#9#8'OnCreate'#7#10'FormCreate'#9'OnKeyDown'#7#11'FormKeyDown'#6'OnS' + +'how'#7#8'FormShow'#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6#6'0.9.' + +'29'#0#8'TToolBar'#7'ToBMain'#4'Left'#2#0#3'Top'#2#0#5'Width'#3' '#3#8'AutoS' + +'ize'#9#12'ButtonHeight'#2#30#11'ButtonWidth'#2#31#7'Caption'#6#6'TBMain'#14 + +'DisabledImages'#7#9'ILMainDis'#6'Images'#7#6'ILMain'#8'TabOrder'#2#0#8'Wrap' + +'able'#8#0#11'TToolButton'#11'TBPageFirst'#4'Left'#2#1#3'Top'#2#2#6'Action'#7 + +#11'ACPageFirst'#7'Grouped'#9#14'ParentShowHint'#8#8'ShowHint'#9#0#0#11'TToo' + +'lButton'#14'TBPagePrevious'#4'Left'#2' '#3'Top'#2#2#6'Action'#7#14'ACPagePr' + +'evious'#7'Grouped'#9#14'ParentShowHint'#8#8'ShowHint'#9#0#0#11'TToolButton' + +#10'TBPageNext'#4'Left'#2'?'#3'Top'#2#2#6'Action'#7#10'ACPageNext'#7'Grouped' + +#9#14'ParentShowHint'#8#8'ShowHint'#9#0#0#11'TToolButton'#10'TBPageLast'#4'L' + ,'eft'#2'^'#3'Top'#2#2#6'Action'#7#10'ACPageLast'#7'Grouped'#9#14'ParentShowH' + +'int'#8#8'ShowHint'#9#0#0#11'TToolButton'#11'ToolButton3'#4'Left'#2'}'#3'Top' + +#2#2#5'Width'#2#8#7'Caption'#6#11'ToolButton3'#10'ImageIndex'#2#2#5'Style'#7 + +#12'tbsSeparator'#0#0#11'TToolButton'#11'ToolButton6'#4'Left'#3#198#0#3'Top' + +#2#2#5'Width'#2#8#7'Caption'#6#11'ToolButton6'#10'ImageIndex'#2#3#5'Style'#7 + +#12'tbsSeparator'#0#0#11'TToolButton'#7'TBPrint'#4'Left'#3'M'#1#3'Top'#2#2#6 + +'Action'#7#7'ACPrint'#14'ParentShowHint'#8#8'ShowHint'#9#0#0#11'TToolButton' + +#11'ToolButton4'#4'Left'#3'l'#1#3'Top'#2#2#5'Width'#2#8#7'Caption'#6#11'Tool' + +'Button4'#10'ImageIndex'#2#5#5'Style'#7#12'tbsSeparator'#0#0#11'TToolButton' + +#7'TBClose'#4'Left'#3't'#1#3'Top'#2#2#6'Action'#7#7'ACClose'#14'ParentShowHi' + +'nt'#8#8'ShowHint'#9#0#0#6'TPanel'#6'PNPage'#4'Left'#3#133#0#6'Height'#2#30#3 + +'Top'#2#2#5'Width'#2'A'#10'BevelOuter'#7#6'bvNone'#12'ClientHeight'#2#30#11 + +'ClientWidth'#2'A'#8'TabOrder'#2#0#0#5'TEdit'#6'EDPage'#4'Left'#2#4#6'Height' + +#2#21#3'Top'#2#4#5'Width'#2'*'#6'OnExit'#7#10'EDPageExit'#8'TabOrder'#2#0#4 + +'Text'#6#1'1'#0#0#7'TUpDown'#6'UDPage'#4'Left'#2'.'#6'Height'#2#21#3'Top'#2#4 + +#5'Width'#2#15#9'Associate'#7#6'EDPage'#3'Min'#2#1#8'Position'#2#1#8'TabOrde' + +'r'#2#1#4'Wrap'#8#7'OnClick'#7#11'UDPageClick'#0#0#0#6'TPanel'#7'PNScale'#4 + +'Left'#3#206#0#6'Height'#2#30#3'Top'#2#2#5'Width'#2'x'#10'BevelOuter'#7#6'bv' + +'None'#12'ClientHeight'#2#30#11'ClientWidth'#2'x'#8'TabOrder'#2#1#0#9'TCombo' + +'Box'#8'CoBScale'#4'Left'#2#2#6'Height'#2#21#3'Top'#2#4#5'Width'#2's'#13'Dro' + +'pDownCount'#2#16#10'ItemHeight'#2#13#13'Items.Strings'#1#6#4'25 %'#6#4'50 %' + +#6#4'75 %'#6#5'100 %'#6#5'125 %'#6#5'150 %'#6#5'200 %'#6#5'500 %'#6#10'Whole' + +' Page'#6#10'Page Width'#0#6'OnExit'#7#12'CoBScaleExit'#8'OnSelect'#7#12'CoB' + +'ScaleExit'#8'TabOrder'#2#0#0#0#0#11'TToolButton'#11'ToolButton1'#4'Left'#3 + +'F'#1#3'Top'#2#2#5'Width'#2#7#7'Caption'#6#11'ToolButton1'#5'Style'#7#12'tbs' + +'Separator'#0#0#0#14'TKPrintPreview'#7'Preview'#4'Left'#2#0#6'Height'#3't'#2 + +#3'Top'#2' '#5'Width'#3' '#3#5'Align'#7#8'alClient'#4'Page'#2#0#7'TabStop'#9 + +#8'TabOrder'#2#1#9'OnChanged'#7#14'PreviewChanged'#0#0#10'TImageList'#6'ILMa' + +'in'#6'Height'#2#24#5'Width'#2#24#4'left'#2#16#3'top'#2'6'#6'Bitmap'#10#14'6' + +#0#0'Li'#6#0#0#0#24#0#0#0#24#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0'k'#174#148#255'k'#174#148#255'k'#174#148#255'k'#174#148#255 + +#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0'k'#174#148#255'k'#174 + +#148#255#173#183#184#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#252 + +#254#254#255#252#254#254#255'k'#174#148#255#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0'k'#174#148 + +#255'k'#174#148#255#167#207#192#255#167#207#192#255'k'#174#148#255#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0'k'#174#148#255#247#252#251#255#247#252#251#255 + +'k'#174#148#255#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0'k'#174#148#255'k'#174#148#255#164#206#190#255#245#251#250#255#245 + +#251#250#255#247#252#251#255'k'#174#148#255#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0'k'#174#148#255#241#249#247#255#241#249#247#255'k'#174#148#255#173#183 + +#184#0#173#183#184#0#173#183#184#0'k'#174#148#255'k'#174#148#255#162#205#189 + ,#255#238#248#246#255#236#247#245#255#234#247#244#255#236#247#245#255#239#249 + +#247#255'k'#174#148#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#234 + +#247#244#255#234#247#244#255'k'#174#148#255#173#183#184#0'k'#174#148#255'k' + +#174#148#255#159#204#188#255#230#245#242#255#227#244#240#255#225#243#239#255 + +#224#243#238#255#223#242#237#255#225#243#239#255#231#246#242#255'k'#174#148 + +#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#227#245#240#255#227 + +#245#240#255'k'#174#148#255'k'#174#148#255#156#203#186#255#222#243#237#255 + +#218#242#235#255#215#241#233#255#213#240#232#255#212#239#231#255#211#239#231 + +#255#211#239#231#255#215#241#233#255#223#243#238#255'k'#174#148#255#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0'k'#174#148#255#220#242#237#255#220#242#237#255 + +'k'#174#148#255#216#241#234#255#209#238#231#255#205#237#229#255#203#236#227 + +#255#201#235#226#255#200#235#226#255#200#235#226#255#200#235#226#255#200#235 + +#226#255#205#237#229#255#215#241#234#255'k'#174#148#255#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0'k'#174#148#255#214#241#234#255#214#241#234#255'k'#174#148#255 + +#198#235#226#255#192#233#223#255#190#232#222#255#189#232#221#255#189#232#221 + +#255#189#232#221#255#189#232#221#255#189#232#221#255#189#232#221#255#195#234 + +#224#255#207#238#230#255'k'#174#148#255#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +'k'#174#148#255#160#236#217#255#160#236#217#255'k'#174#148#255'|'#229#203#255 + +'o'#227#197#255'i'#225#195#255'h'#225#194#255'g'#225#194#255'g'#225#194#255 + +'g'#225#194#255'g'#225#194#255'g'#225#194#255'u'#228#200#255#145#233#211#255 + +'k'#174#148#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#160#236 + +#217#255#160#236#217#255'k'#174#148#255#147#234#211#255#128#230#204#255'u' + +#228#200#255'n'#226#197#255'i'#225#195#255'h'#225#194#255'g'#225#194#255'g' + +#225#194#255'g'#225#194#255'u'#228#200#255#145#233#211#255'k'#174#148#255#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#160#236#217#255#160#236#217 + +#255'k'#174#148#255'k'#174#148#255#129#200#176#255#142#233#210#255#128#230 + +#204#255'u'#228#200#255'n'#226#197#255'i'#225#195#255'h'#225#194#255'g'#225 + +#194#255'u'#228#200#255#145#233#211#255'k'#174#148#255#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0'k'#174#148#255#160#236#217#255#160#236#217#255'k'#174#148#255 + +#173#183#184#128'k'#174#148#255'k'#174#148#255#129#200#176#255#142#233#210 + +#255#128#230#204#255'u'#228#200#255'n'#226#197#255'i'#225#195#255'v'#228#200 + +#255#145#233#211#255'k'#174#148#255#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174 + +#148#255#160#236#217#255#160#236#217#255'k'#174#148#255#173#183#184#0#173#183 + +#184#128#173#183#184#128'k'#174#148#255'k'#174#148#255#129#200#176#255#142 + +#233#210#255#128#230#204#255'v'#228#200#255'~'#230#203#255#151#234#213#255'k' + +#174#148#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#170#238#221 + +#255#170#238#221#255'k'#174#148#255#173#183#184#0#173#183#184#0#173#183#184#0 + +#173#183#184#128#173#183#184#128'k'#174#148#255'k'#174#148#255#129#200#176 + +#255#145#233#211#255#147#234#212#255#168#238#220#255'k'#174#148#255#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0'k'#174#148#255#191#242#229#255#191#242#229#255 + +'k'#174#148#255#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#128#173#183#184#128'k'#174#148#255'k'#174#148#255#138 + +#202#180#255#144#202#182#255'k'#174#148#255#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0'k'#174#148#255'k'#174#148#255'k'#174#148#255'k'#174#148#255#173#183 + +#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0 + +#173#183#184#0#173#183#184#128#173#183#184#128'k'#174#148#255'k'#174#148#255 + +#173#183#184#128#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#128#173#183 + +#184#128#173#183#184#128#173#183#184#128#173#183#184#0#173#183#184#0#173#183 + +#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0 + +#173#183#184#0#173#183#184#128#173#183#184#128#173#183#184#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + ,#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#0 + +#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183 + +#184#0'k'#174#148#255'k'#174#148#255'k'#174#148#255#173#183#184#0#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183 + +#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0 + +#173#183#184#0'k'#174#148#255'k'#174#148#255#167#207#191#255#252#254#253#255 + +#167#207#192#255'k'#174#148#255#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#173#183 + +#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0 + +#173#183#184#0#173#183#184#0'k'#174#148#255'k'#174#148#255#164#206#190#255 + +#245#251#250#255#244#251#249#255#244#251#250#255#247#252#251#255'k'#174#148 + +#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0'k'#174#148#255'k'#174 + +#148#255#162#205#189#255#238#248#246#255#236#247#245#255#234#247#244#255#233 + +#246#244#255#235#247#244#255#239#249#247#255'k'#174#148#255#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0 + +'k'#174#148#255'k'#174#148#255#159#204#188#255#230#245#242#255#227#244#240 + +#255#225#243#239#255#224#243#238#255#223#242#237#255#222#242#237#255#225#243 + +#239#255#231#246#242#255'k'#174#148#255#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#173#183#184#0#173#183#184#0'k'#174#148#255'k'#174#148#255#156#203#186#255 + +#222#243#237#255#218#242#235#255#215#241#233#255#213#240#232#255#212#239#231 + +#255#211#239#231#255#211#239#231#255#211#239#231#255#215#241#233#255#223#243 + +#238#255'k'#174#148#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#0'k' + +#174#148#255#156#203#186#255#216#241#234#255#209#238#231#255#205#237#229#255 + +#203#236#227#255#201#235#226#255#200#235#226#255#200#235#226#255#200#235#226 + +#255#200#235#226#255#200#235#226#255#205#237#229#255#215#241#234#255'k'#174 + +#148#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255 + ,#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#156#203#186#255 + +#209#239#232#255#198#235#226#255#192#233#223#255#190#232#222#255#189#232#221 + +#255#189#232#221#255#189#232#221#255#189#232#221#255#189#232#221#255#189#232 + +#221#255#189#232#221#255#195#234#224#255#207#238#230#255'k'#174#148#255#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#140#202#181#255#150#234#213 + +#255'|'#229#203#255'o'#227#197#255'i'#225#195#255'h'#225#194#255'g'#225#194 + +#255'g'#225#194#255'g'#225#194#255'g'#225#194#255'g'#225#194#255'g'#225#194 + +#255'u'#228#200#255#145#233#211#255'k'#174#148#255#255#255#255#0#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#173#183#184#128'k'#174#148#255#135#201#178#255#147#234#211#255#128 + +#230#204#255'u'#228#200#255'n'#226#197#255'i'#225#195#255'h'#225#194#255'g' + +#225#194#255'g'#225#194#255'g'#225#194#255'g'#225#194#255'u'#228#200#255#145 + +#233#211#255'k'#174#148#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#0 + +#173#183#184#128'k'#174#148#255'k'#174#148#255#129#200#176#255#142#233#210 + +#255#128#230#204#255'u'#228#200#255'n'#226#197#255'i'#225#195#255'h'#225#194 + +#255'g'#225#194#255'g'#225#194#255'u'#228#200#255#145#233#211#255'k'#174#148 + +#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#0#173#183#184#0#173 + +#183#184#128#173#183#184#128'k'#174#148#255'k'#174#148#255#129#200#176#255 + +#142#233#210#255#128#230#204#255'u'#228#200#255'n'#226#197#255'i'#225#195#255 + +'h'#225#194#255'u'#228#200#255#145#233#211#255'k'#174#148#255#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183 + +#184#0#173#183#184#128#173#183#184#128'k'#174#148#255'k'#174#148#255#129#200 + +#176#255#142#233#210#255#128#230#204#255'u'#228#200#255'o'#227#197#255'y'#229 + +#201#255#149#234#212#255'k'#174#148#255#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#128#173#183#184#128'k'#174#148#255'k'#174#148#255#129 + +#200#176#255#143#233#210#255#132#231#206#255#139#232#209#255#164#237#219#255 + +'k'#174#148#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#0#173#183 + +#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0 + +#173#183#184#0#173#183#184#128#173#183#184#128'k'#174#148#255'k'#174#148#255 + +#132#200#178#255#170#238#221#255#142#202#181#255'k'#174#148#255#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183 + +#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0 + +#173#183#184#0#173#183#184#128#173#183#184#128'k'#174#148#255'k'#174#148#255 + +'k'#174#148#255#173#183#184#128#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#173#183 + +#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0 + +#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#128#173#183#184#128#173#183#184#128#173#183#184#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + ,#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#173 + +#183#184#0'k'#174#148#255'k'#174#148#255'k'#174#148#255#173#183#184#0#173#183 + +#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0 + +#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#167#207#192#255#252#254#253 + +#255#167#207#191#255'k'#174#148#255'k'#174#148#255#173#183#184#0#173#183#184 + +#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#0#173#183#184#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +'k'#174#148#255#247#252#251#255#244#251#250#255#244#251#249#255#245#251#250 + +#255#164#206#190#255'k'#174#148#255'k'#174#148#255#173#183#184#0#173#183#184 + +#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#239#249#247 + +#255#235#247#244#255#233#246#244#255#234#247#244#255#236#247#245#255#238#248 + +#246#255#162#205#189#255'k'#174#148#255'k'#174#148#255#173#183#184#0#173#183 + +#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0'k'#174#148#255#231#246#242#255#225#243#239#255#222 + +#242#237#255#223#242#237#255#224#243#238#255#225#243#239#255#227#244#240#255 + +#230#245#242#255#159#204#188#255'k'#174#148#255'k'#174#148#255#173#183#184#0 + +#173#183#184#0#173#183#184#0#173#183#184#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0'k'#174#148#255#223#243#238#255#215#241#233#255#211#239#231#255#211#239 + +#231#255#211#239#231#255#212#239#231#255#213#240#232#255#215#241#233#255#218 + +#242#235#255#222#243#237#255#156#203#186#255'k'#174#148#255'k'#174#148#255 + +#173#183#184#0#173#183#184#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148 + +#255#215#241#234#255#205#237#229#255#200#235#226#255#200#235#226#255#200#235 + +#226#255#200#235#226#255#200#235#226#255#201#235#226#255#203#236#227#255#205 + +#237#229#255#209#238#231#255#216#241#234#255#156#203#186#255'k'#174#148#255 + +#173#183#184#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#207#238 + +#230#255#195#234#224#255#189#232#221#255#189#232#221#255#189#232#221#255#189 + +#232#221#255#189#232#221#255#189#232#221#255#189#232#221#255#190#232#222#255 + +#192#233#223#255#198#235#226#255#209#239#232#255#156#203#186#255'k'#174#148 + +#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#145#233#211#255'u' + +#228#200#255'g'#225#194#255'g'#225#194#255'g'#225#194#255'g'#225#194#255'g' + +#225#194#255'g'#225#194#255'h'#225#194#255'i'#225#195#255'o'#227#197#255'|' + +#229#203#255#150#234#213#255#140#202#181#255'k'#174#148#255#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0'k'#174#148#255#145#233#211#255'u'#228#200#255'g'#225#194 + +#255'g'#225#194#255'g'#225#194#255'g'#225#194#255'h'#225#194#255'i'#225#195 + +#255'n'#226#197#255'u'#228#200#255#128#230#204#255#147#234#211#255#135#201 + +#178#255'k'#174#148#255#173#183#184#128#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +'k'#174#148#255#145#233#211#255'u'#228#200#255'g'#225#194#255'g'#225#194#255 + +'h'#225#194#255'i'#225#195#255'n'#226#197#255'u'#228#200#255#128#230#204#255 + ,#142#233#210#255#129#200#176#255'k'#174#148#255'k'#174#148#255#173#183#184 + +#128#173#183#184#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#145 + +#233#211#255'u'#228#200#255'h'#225#194#255'i'#225#195#255'n'#226#197#255'u' + +#228#200#255#128#230#204#255#142#233#210#255#129#200#176#255'k'#174#148#255 + +'k'#174#148#255#173#183#184#128#173#183#184#128#173#183#184#0#173#183#184#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#149#234#212#255'y'#229 + +#201#255'o'#227#197#255'u'#228#200#255#128#230#204#255#142#233#210#255#129 + +#200#176#255'k'#174#148#255'k'#174#148#255#173#183#184#128#173#183#184#128 + +#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0'k'#174#148#255#164#237#219#255#139#232#209#255#132#231 + +#206#255#143#233#210#255#129#200#176#255'k'#174#148#255'k'#174#148#255#173 + +#183#184#128#173#183#184#128#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#0#173#183#184#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +'k'#174#148#255#142#202#181#255#170#238#221#255#132#200#178#255'k'#174#148 + +#255'k'#174#148#255#173#183#184#128#173#183#184#128#173#183#184#0#173#183#184 + +#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#128'k'#174#148 + +#255'k'#174#148#255'k'#174#148#255#173#183#184#128#173#183#184#128#173#183 + +#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0 + +#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#173#183#184#0#173#183#184#128#173#183#184#128#173#183 + +#184#128#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184 + +#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#173#183#184#0'k'#174#148#255'k'#174#148#255#173#183 + +#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0 + ,#173#183#184#0#173#183#184#0#173#183#184#0'k'#174#148#255'k'#174#148#255'k' + +#174#148#255'k'#174#148#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255 + +#167#207#192#255#167#207#192#255'k'#174#148#255'k'#174#148#255#173#183#184#0 + +#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0'k'#174#148#255#252#254#254#255#252#254#254#255'k'#174#148#255#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#247#252#251#255#245#251#250 + +#255#245#251#250#255#164#206#190#255'k'#174#148#255'k'#174#148#255#173#183 + +#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0'k'#174#148#255 + +#247#252#251#255#247#252#251#255'k'#174#148#255#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0'k'#174#148#255#239#249#247#255#236#247#245#255#234#247#244#255#236 + +#247#245#255#238#248#246#255#162#205#189#255'k'#174#148#255'k'#174#148#255 + +#173#183#184#0#173#183#184#0#173#183#184#0'k'#174#148#255#241#249#247#255#241 + +#249#247#255'k'#174#148#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255 + +#231#246#242#255#225#243#239#255#223#242#237#255#224#243#238#255#225#243#239 + +#255#227#244#240#255#230#245#242#255#159#204#188#255'k'#174#148#255'k'#174 + +#148#255#173#183#184#0'k'#174#148#255#234#247#244#255#234#247#244#255'k'#174 + +#148#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#223#243#238#255 + +#215#241#233#255#211#239#231#255#211#239#231#255#212#239#231#255#213#240#232 + +#255#215#241#233#255#218#242#235#255#222#243#237#255#156#203#186#255'k'#174 + +#148#255'k'#174#148#255#227#245#240#255#227#245#240#255'k'#174#148#255#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#215#241#234#255#205#237#229 + +#255#200#235#226#255#200#235#226#255#200#235#226#255#200#235#226#255#201#235 + +#226#255#203#236#227#255#205#237#229#255#209#238#231#255#216#241#234#255'k' + +#174#148#255#220#242#237#255#220#242#237#255'k'#174#148#255#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0'k'#174#148#255#207#238#230#255#195#234#224#255#189#232 + +#221#255#189#232#221#255#189#232#221#255#189#232#221#255#189#232#221#255#189 + +#232#221#255#190#232#222#255#192#233#223#255#198#235#226#255'k'#174#148#255 + +#214#241#234#255#214#241#234#255'k'#174#148#255#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0'k'#174#148#255#145#233#211#255'u'#228#200#255'g'#225#194#255'g' + +#225#194#255'g'#225#194#255'g'#225#194#255'g'#225#194#255'h'#225#194#255'i' + +#225#195#255'o'#227#197#255'|'#229#203#255'k'#174#148#255#160#236#217#255#160 + +#236#217#255'k'#174#148#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255 + +#145#233#211#255'u'#228#200#255'g'#225#194#255'g'#225#194#255'g'#225#194#255 + +'h'#225#194#255'i'#225#195#255'n'#226#197#255'u'#228#200#255#128#230#204#255 + +#147#234#211#255'k'#174#148#255#160#236#217#255#160#236#217#255'k'#174#148 + +#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#145#233#211#255'u' + +#228#200#255'g'#225#194#255'h'#225#194#255'i'#225#195#255'n'#226#197#255'u' + +#228#200#255#128#230#204#255#142#233#210#255#129#200#176#255'k'#174#148#255 + +'k'#174#148#255#160#236#217#255#160#236#217#255'k'#174#148#255#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0'k'#174#148#255#145#233#211#255'v'#228#200#255'i'#225 + +#195#255'n'#226#197#255'u'#228#200#255#128#230#204#255#142#233#210#255#129 + +#200#176#255'k'#174#148#255'k'#174#148#255#173#183#184#128'k'#174#148#255#160 + +#236#217#255#160#236#217#255'k'#174#148#255#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0'k'#174#148#255#151#234#213#255'~'#230#203#255'v'#228#200#255#128#230 + +#204#255#142#233#210#255#129#200#176#255'k'#174#148#255'k'#174#148#255#173 + +#183#184#128#173#183#184#128#173#183#184#0'k'#174#148#255#160#236#217#255#160 + +#236#217#255'k'#174#148#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255 + +#168#238#220#255#147#234#212#255#145#233#211#255#129#200#176#255'k'#174#148 + +#255'k'#174#148#255#173#183#184#128#173#183#184#128#173#183#184#0#173#183#184 + +#0#173#183#184#0'k'#174#148#255#170#238#221#255#170#238#221#255'k'#174#148 + +#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + ,#255#255#255#0#255#255#255#0#255#255#255#0'k'#174#148#255#144#202#182#255#138 + +#202#180#255'k'#174#148#255'k'#174#148#255#173#183#184#128#173#183#184#128 + +#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0'k'#174 + +#148#255#191#242#229#255#191#242#229#255'k'#174#148#255#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#173#183#184#128'k'#174#148#255'k'#174#148#255#173#183#184#128 + +#173#183#184#128#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#0#173#183#184#0'k'#174#148#255'k'#174#148#255'k'#174 + +#148#255'k'#174#148#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#0#173 + +#183#184#128#173#183#184#128#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183 + +#184#0#173#183#184#128#173#183#184#128#173#183#184#128#173#183#184#128#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#239#199#165#0#239#199 + +#165#0#239#199#165#0#239#199#165#0#239#199#165#0#239#199#165#16#239#200#166 + +#235#241#204#171#251#241#203#171#251#241#203#170#251#241#204#170#251#241#203 + +#171#251#241#203#171#251#241#203#171#251#241#203#170#251#241#203#170#251#241 + +#204#171#251#239#200#167#235#239#199#166#16#239#199#166#0#239#199#166#0#239 + +#199#166#0#239#199#166#0#239#199#166#0#244#201#164#0#244#202#164#0#240#200 + +#165#0#238#199#165#0#238#199#165#0#237#197#163#16#242#207#174#239#253#229#200 + +#255#251#227#199#255#252#227#198#255#251#227#198#255#251#227#199#255#251#227 + +#199#255#251#227#199#255#252#227#198#255#252#227#198#255#252#228#200#255#243 + +#207#176#239#239#199#165#16#240#201#168#0#239#201#168#0#241#202#167#0#246#203 + +#167#0#245#203#167#0#198#185#174#0#196#184#175#0#232#197#167#0#245#202#165#0 + +#240#201#166#0#239#199#164#16#242#206#174#239#251#225#195#255#250#223#193#255 + +#250#223#193#255#251#223#193#255#251#223#193#255#250#223#194#255#251#223#193 + +#255#250#223#193#255#250#223#193#255#251#224#194#255#244#209#176#239#240#203 + +#169#16#241#204#170#0#247#206#169#0#233#201#172#0#199#188#179#0#201#189#178#0 + +#175#177#179#0#175#177#179#0#188#188#187#0#200#187#176#0#243#203#166#0#241 + +#202#166#16#243#208#173#239#250#223#191#255#250#222#190#255#250#221#189#255 + +#250#221#189#255#250#222#190#255#250#222#190#255#250#221#189#255#250#222#189 + +#255#250#222#190#255#250#222#191#255#245#210#177#239#244#206#172#16#245#207 + +#172#0#200#188#178#0#190#189#189#0#179#181#183#0#179#181#183#0#178#178#178#0 + +#178#178#178#0#188#188#188#0#175#178#181#0#200#187#174#0#242#203#168#16#245 + +#209#173#239#250#221#187#255#250#220#186#255#250#220#186#255#250#221#186#255 + +#249#220#186#255#250#221#186#255#250#220#187#255#249#219#186#255#250#220#186 + +#255#250#221#186#255#248#212#177#239#248#210#174#16#201#188#177#0#175#177#180 + +#0#190#190#190#0#182#182#182#0#182#182#182#0#178#178#178#0#178#178#178#0#188 + +#188#188#0#180#180#180#0#170#175#178#0#235#200#174#15#251#212#174#239#249#218 + +#183#255#250#218#182#255#249#217#182#255#250#218#183#255#249#219#183#255#249 + +#219#183#255#249#218#183#255#249#218#183#255#250#218#183#255#251#218#182#255 + +#246#213#177#239#200#189#174#13#172#175#178#0#180#180#180#0#190#190#190#0#182 + +#182#182#0#182#182#182#0#178#178#178#0#178#178#178#0#187#188#187#0#180#179 + +#180#27#181#176#179#16#140#186#160#16#234#210#171#237#252#217#180#255#248#217 + +#180#255#249#217#180#255#248#217#179#255#249#217#180#255#249#217#180#255#248 + +#217#179#255#249#217#179#255#249#217#180#255#251#218#180#255#241#211#176#240 + ,#173#177#174'#'#180#177#179#16#180#179#179#13#189#190#189#0#182#182#182#0#182 + +#182#182#0#179#179#179#0#178#178#178#7#204#194#197#157#156#205#189#243'3'#192 + +#149#241'U'#186#150#239#235#199#160#254#255#205#165#255#250#204#164#255#250 + +#204#164#255#250#204#164#255#250#204#164#255#250#204#164#255#250#204#164#255 + +#250#204#164#255#250#204#164#255#254#205#165#255#239#201#161#254'['#185#150 + +#242'/'#186#143#241#163#203#190#235#206#197#200#165#182#182#182#16#183#183 + +#183#0#190#190#190#0#187#187#187'Z'#246#237#240#254#187#236#220#255'1'#210 + +#161#255'G'#213#166#255#169#181#138#255#184#181#140#255#181#182#140#255#181 + +#182#140#255#181#182#140#255#181#182#140#255#181#182#140#255#181#182#140#255 + +#181#182#141#255#181#182#140#255#184#181#140#255#168#183#140#255'2'#202#153 + +#255#26#194#141#255#201#239#225#255#251#241#244#255#192#192#192'e'#195#195 + +#195#0#193#193#193#0#191#190#190'g'#251#244#246#255#173#231#212#255';'#207 + +#161#255'j'#239#200#255'P'#215#173#255'P'#213#172#255'P'#214#172#255'P'#214 + +#172#255'P'#213#172#255'P'#213#172#255'P'#213#172#255'P'#214#172#255'P'#214 + +#173#255'P'#214#172#255'Q'#213#172#255'M'#215#173#255'a'#236#195#255'<'#203 + +#156#255#196#234#220#255#255#246#250#255#197#197#197'q'#200#200#200#0#193#193 + +#193#0#190#190#190'm'#251#244#246#255#177#230#212#255':'#203#157#255't'#244 + +#207#255'n'#241#204#255'n'#242#204#255'n'#241#204#255'n'#241#204#255'n'#242 + +#204#255'n'#242#204#255'n'#242#204#255'n'#241#204#255'n'#241#204#255'n'#241 + +#204#255'n'#242#204#255'o'#241#204#255'v'#244#208#255'<'#200#153#255#197#231 + +#218#255#255#246#250#255#196#196#196'v'#199#199#199#0#188#188#188#0#185#185 + +#185'p'#249#242#245#255#188#231#215#255'3'#194#145#255'8'#203#156#255'$'#198 + +#146#255'&'#200#149#255'&'#200#149#255'&'#200#149#255'&'#200#149#255'&'#200 + +#149#255'&'#200#149#255'&'#200#149#255'&'#200#149#255'&'#200#149#255'&'#200 + +#149#255'#'#197#146#255'9'#205#159#255'8'#191#144#255#199#231#217#255#252#244 + +#247#255#189#189#189'v'#192#192#192#0#182#182#182#0#179#179#179'q'#239#232 + +#235#255#192#229#215#255'+'#180#131#255'*'#178#129#255#27#171'v'#255#29#173 + +'y'#255#29#173'y'#255#29#173'y'#255#29#173'y'#255#29#173'y'#255#29#173'y'#255 + +#29#173'y'#255#29#173'y'#255#29#173'y'#255#29#173'y'#255#27#171'v'#255'*'#178 + +#129#255','#175#127#255#201#230#218#255#238#231#235#255#181#181#181'u'#184 + +#184#184#0#179#179#179#0#176#176#176't'#229#222#225#255#192#226#211#255'+' + +#178#127#255'G'#200#156#255'@'#192#146#255'A'#192#146#255'A'#192#146#255'A' + +#192#146#255'A'#192#146#255'A'#192#147#255'A'#192#147#255'A'#192#147#255'A' + +#192#147#255'A'#192#147#255'A'#192#147#255'@'#191#146#255'G'#201#156#255',' + +#174'}'#255#197#226#212#255#226#219#222#255#176#176#176'v'#179#179#179#0#173 + +#173#173#0#170#170#170#127#214#210#212#255#231#238#235#255'm'#191#157#255'0' + +#164'u'#255':'#169'{'#255':'#169'z'#255':'#168'z'#255':'#168'z'#255':'#167'z' + +#255':'#168'y'#255':'#168'y'#255':'#167'y'#255';'#167'z'#255';'#167'z'#255';' + +#167'z'#255';'#167'z'#255'0'#162'r'#255'}'#196#166#255#237#239#238#255#209 + +#206#207#255#170#170#170#127#173#173#173#0#183#183#183#0#170#170#170#128#205 + +#205#205#255#225#224#224#255#235#234#235#255#227#232#230#255#234#240#238#255 + +#228#236#235#255#228#236#235#255#228#236#235#255#228#236#234#255#228#236#234 + +#255#228#236#234#255#228#236#234#255#228#235#234#255#228#235#234#255#227#235 + +#233#255#228#236#234#255#239#240#239#255#206#224#217#255#200#212#207#255#203 + +#201#202#255#170#170#170#128#183#183#183#0'ppp'#0#184#184#184#128#203#203#203 + +#255#216#216#216#255#214#214#214#255#205#205#206#255#150#145#144#255#183#169 + +#163#255#182#168#162#255#182#168#162#255#182#168#162#255#181#168#161#255#181 + +#168#162#255#181#168#162#255#181#167#161#255#181#167#162#255#181#168#162#255 + +#172#159#154#255#158#152#154#255#156#193#177#255#174#198#188#255#203#199#201 + +#255#184#184#184#128'ppp'#0#0#0#0#0'nnn'#130#212#212#212#255#212#212#212#255 + +#213#213#213#255#190#192#194#255'UKC'#255#186#148'r'#255#182#147's'#255#182 + +#147'u'#255#182#149'w'#255#182#151'{'#255#182#152'|'#255#182#152'~'#255#183 + +#154#128#255#183#154#133#255#186#159#137#255#163#139'w'#255'XWV'#255#216#212 + +#215#255#210#208#209#255#208#208#208#255'nnn'#130#0#0#0#0#0#0#0#7'???F'#180 + +#180#180#224#211#211#211#255#215#215#215#255#187#190#192#255'mbW'#255#239#191 + +#145#255#234#188#145#255#234#189#148#255#234#190#150#255#234#193#154#255#234 + +#195#159#255#234#197#162#255#234#198#165#255#234#200#170#255#237#206#176#255 + +#213#185#159#255'jhf'#255#213#214#215#255#210#210#210#255#184#184#184#233'DD' + +'DR'#0#0#0#5#0#0#0#25#0#0#0'%>>>Qwww'#179'uuu'#182#132#135#138#185#154#142 + +#130#209#255#212#164#255#255#208#163#255#255#209#164#255#255#209#167#255#255 + +#212#169#255#255#213#174#255#255#216#177#255#255#217#179#255#255#218#182#255 + +#255#223#188#255#247#214#184#251'xvt'#194'tuu'#180'yyy'#180'CCCW'#0#0#0'$'#0 + +#0#0#25#0#0#0#4#0#0#0#5#0#0#0#0#0#0#0#0#0#0#0#0#16#18#18#0'g]RC'#255#240#196 + +#255#255#230#188#255#255#230#188#255#255#230#189#255#255#231#190#255#255#232 + ,#191#255#255#234#195#255#255#234#195#255#255#235#197#255#255#239#202#255#255 + +#227#193#254'''%#'#12#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#5#0#0#0#4#0#0#0#0#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#15#5#3#2',+& T+$'#30'Z+$'#30'Y+$'#30'Y+$'#30 + +'Y+%'#30'Y+%'#31'Y+%'#31'Y+%'#31'Y+& Z''"'#29'O'#0#0#0'"'#0#0#0#9#0#0#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#173#183#184#0#173#183#184#0'FF'#193 + +#255'FF'#193#255#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0'FF'#193#255'FF'#193#255 + +#173#183#184#0#173#183#184#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#173#183 + +#184#0'FF'#193#255#145#145#219#255#145#145#219#255'FF'#193#255#173#183#184#0 + +#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0'FF' + +#193#255#145#145#219#255#145#145#219#255'FF'#193#255#173#183#184#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0'FF'#193#255#143#143#219#255#243#243#255#255#242 + +#242#255#255#142#142#219#255'FF'#193#255#173#183#184#0#173#183#184#0#173#183 + +#184#0#173#183#184#0'FF'#193#255#142#142#219#255#242#242#255#255#243#243#255 + +#255#143#143#219#255'FF'#193#255#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'FF' + +#193#255#140#140#219#255#233#233#255#255#230#230#255#255#231#231#255#255#138 + +#138#219#255'FF'#193#255#173#183#184#0#173#183#184#0'FF'#193#255#138#138#219 + +#255#231#231#255#255#230#230#255#255#233#233#255#255#140#140#219#255'FF'#193 + +#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#128'FF'#193#255#135 + +#135#219#255#220#220#255#255#217#217#255#255#219#219#255#255#133#133#219#255 + +'FF'#193#255'FF'#193#255#133#133#219#255#219#219#255#255#217#217#255#255#220 + +#220#255#255#135#135#219#255'FF'#193#255#173#183#184#128#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#173#183#184#0#173#183#184#128'FF'#193#255#131#131#219 + +#255#207#207#255#255#203#203#255#255#203#203#255#255#204#204#255#255#204#204 + +#255#255#203#203#255#255#203#203#255#255#207#207#255#255#131#131#219#255'FF' + +#193#255#173#183#184#128#173#183#184#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#173#183#184#0#173#183#184#0#173#183#184#128'FF'#193#255'||'#219#255#191#191 + +#255#255#185#185#255#255#184#184#255#255#184#184#255#255#185#185#255#255#191 + +#191#255#255'||'#219#255'FF'#193#255#173#183#184#128#173#183#184#0#173#183 + +#184#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#128'FF'#193#255#181#181#255#255#171#171#255#255#168 + +#168#255#255#168#168#255#255#171#171#255#255#181#181#255#255'FF'#193#255#173 + +#183#184#128#173#183#184#0#173#183#184#0#173#183#184#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + ,#255#255#255#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0'FF' + +#193#255'rr'#255#255'__'#255#255'XX'#255#255'XX'#255#255'__'#255#255'rr'#255 + +#255'FF'#193#255#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#173#183#184#0#173#183#184#0#173#183#184#0 + +'FF'#193#255'aa'#219#255'nn'#255#255'bb'#255#255'__'#255#255'__'#255#255'bb' + +#255#255'nn'#255#255'aa'#219#255'FF'#193#255#173#183#184#0#173#183#184#0#173 + +#183#184#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#0#173#183#184#0 + +'FF'#193#255'gg'#219#255'{{'#255#255'pp'#255#255'nn'#255#255'rr'#255#255'rr' + +#255#255'nn'#255#255'pp'#255#255'{{'#255#255'gg'#219#255'FF'#193#255#173#183 + +#184#0#173#183#184#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#0'FF' + +#193#255'jj'#219#255#128#128#255#255'uu'#255#255'{{'#255#255'aa'#219#255'FF' + +#193#255'FF'#193#255'aa'#219#255'{{'#255#255'uu'#255#255#128#128#255#255'jj' + +#219#255'FF'#193#255#173#183#184#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'FF' + +#193#255'tt'#219#255#142#142#255#255'zz'#255#255#128#128#255#255'gg'#219#255 + +'FF'#193#255#173#183#184#128#173#183#184#128'FF'#193#255'gg'#219#255#128#128 + +#255#255'zz'#255#255#142#142#255#255'tt'#219#255'FF'#193#255#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0'FF'#193#255'uu'#219#255#152#152#255#255#142#142#255 + +#255'jj'#219#255'FF'#193#255#173#183#184#128#173#183#184#0#173#183#184#0#173 + +#183#184#128'FF'#193#255'jj'#219#255#142#142#255#255#152#152#255#255'uu'#219 + +#255'FF'#193#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#128'FF'#193 + +#255'uu'#219#255'tt'#219#255'FF'#193#255#173#183#184#128#173#183#184#0#173 + +#183#184#0#173#183#184#0#173#183#184#0#173#183#184#128'FF'#193#255'tt'#219 + +#255'uu'#219#255'FF'#193#255#173#183#184#128#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#173#183#184#0#173#183#184#128'FF'#193#255'FF'#193#255#173#183#184#128 + +#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#128'FF'#193#255'FF'#193#255#173#183#184#128#173#183 + +#184#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#173#183#184#0#173#183#184#0#173 + +#183#184#128#173#183#184#128#173#183#184#0#173#183#184#0#173#183#184#0#173 + +#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183#184#0#173#183 + +#184#128#173#183#184#128#173#183#184#0#173#183#184#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#11 + +'TActionList'#6'ALMain'#6'Images'#7#6'ILMain'#4'left'#2'8'#3'top'#2'6'#0#7'T' + +'Action'#11'ACPageFirst'#4'Hint'#6#10'First page'#10'ImageIndex'#2#0#9'OnExe' + +'cute'#7#18'ACPageFirstExecute'#8'OnUpdate'#7#17'ACPageFirstUpdate'#0#0#7'TA' + +'ction'#14'ACPagePrevious'#7'Caption'#6#13'Previous page'#4'Hint'#6#13'Previ' + +'ous page'#10'ImageIndex'#2#1#9'OnExecute'#7#21'ACPagePreviousExecute'#8'OnU' + +'pdate'#7#17'ACPageFirstUpdate'#0#0#7'TAction'#10'ACPageNext'#7'Caption'#6#9 + +'Next page'#4'Hint'#6#9'Next page'#10'ImageIndex'#2#2#9'OnExecute'#7#17'ACPa' + +'geNextExecute'#8'OnUpdate'#7#16'ACPageNextUpdate'#0#0#7'TAction'#10'ACPageL' + +'ast'#7'Caption'#6#9'Last page'#4'Hint'#6#9'Last page'#10'ImageIndex'#2#3#9 + +'OnExecute'#7#17'ACPageLastExecute'#8'OnUpdate'#7#16'ACPageNextUpdate'#0#0#7 + +'TAction'#7'ACPrint'#7'Caption'#6#5'Print'#4'Hint'#6#5'Print'#10'ImageIndex' + +#2#4#9'OnExecute'#7#14'ACPrintExecute'#8'OnUpdate'#7#13'ACPrintUpdate'#0#0#7 + ,'TAction'#7'ACClose'#7'Caption'#6#5'Close'#4'Hint'#6#13'Close preview'#10'Im' + +'ageIndex'#2#5#9'OnExecute'#7#14'ACCloseExecute'#8'OnUpdate'#7#13'ACCloseUpd' + +'ate'#0#0#0#10'TImageList'#9'ILMainDis'#6'Height'#2#24#5'Width'#2#24#4'left' + +#2'`'#3'top'#2'6'#6'Bitmap'#10#14'6'#0#0'Li'#6#0#0#0#24#0#0#0#24#0#0#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140#255#140#140 + +#140#255#140#140#140#255#140#140#140#255#178#178#178#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0 + +#178#178#178#0#140#140#140#255#140#140#140#255#178#178#178#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#140#140#140#255#253#253#253#255#253#253#253#255#140 + +#140#140#255#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#178#178#178#0#140#140#140#255#140#140#140#255#187#187 + +#187#255#187#187#187#255#140#140#140#255#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#140#140#140#255#249#249#249#255#249#249#249#255#140#140#140#255#178#178#178 + +#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#140#140#140#255 + +#140#140#140#255#185#185#185#255#248#248#248#255#248#248#248#255#249#249#249 + +#255#140#140#140#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140#255#245 + +#245#245#255#245#245#245#255#140#140#140#255#178#178#178#0#178#178#178#0#178 + +#178#178#0#140#140#140#255#140#140#140#255#183#183#183#255#243#243#243#255 + +#241#241#241#255#240#240#240#255#241#241#241#255#244#244#244#255#140#140#140 + +#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140#255#240#240#240#255 + +#240#240#240#255#140#140#140#255#178#178#178#0#140#140#140#255#140#140#140 + +#255#181#181#181#255#237#237#237#255#235#235#235#255#234#234#234#255#233#233 + +#233#255#232#232#232#255#234#234#234#255#238#238#238#255#140#140#140#255#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#140#140#140#255#236#236#236#255#236#236 + +#236#255#140#140#140#255#140#140#140#255#179#179#179#255#232#232#232#255#230 + +#230#230#255#228#228#228#255#226#226#226#255#225#225#225#255#225#225#225#255 + +#225#225#225#255#228#228#228#255#233#233#233#255#140#140#140#255#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#140#140#140#255#231#231#231#255#231#231#231#255#140 + +#140#140#255#228#228#228#255#223#223#223#255#221#221#221#255#219#219#219#255 + +#218#218#218#255#217#217#217#255#217#217#217#255#217#217#217#255#217#217#217 + +#255#221#221#221#255#228#228#228#255#140#140#140#255#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#140#140#140#255#227#227#227#255#227#227#227#255#140#140#140 + +#255#216#216#216#255#212#212#212#255#211#211#211#255#210#210#210#255#210#210 + +#210#255#210#210#210#255#210#210#210#255#210#210#210#255#210#210#210#255#214 + +#214#214#255#222#222#222#255#140#140#140#255#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#140#140#140#255#198#198#198#255#198#198#198#255#140#140#140#255#176 + +#176#176#255#169#169#169#255#165#165#165#255#164#164#164#255#164#164#164#255 + +#164#164#164#255#164#164#164#255#164#164#164#255#164#164#164#255#172#172#172 + ,#255#189#189#189#255#140#140#140#255#255#255#255#0#255#255#255#0#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#140 + +#140#140#255#198#198#198#255#198#198#198#255#140#140#140#255#190#190#190#255 + +#179#179#179#255#172#172#172#255#168#168#168#255#165#165#165#255#164#164#164 + +#255#164#164#164#255#164#164#164#255#164#164#164#255#172#172#172#255#189#189 + +#189#255#140#140#140#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140 + +#255#198#198#198#255#198#198#198#255#140#140#140#255#140#140#140#255#164#164 + +#164#255#187#187#187#255#179#179#179#255#172#172#172#255#168#168#168#255#165 + +#165#165#255#164#164#164#255#164#164#164#255#172#172#172#255#189#189#189#255 + +#140#140#140#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140#255#198#198 + +#198#255#198#198#198#255#140#140#140#255#178#178#178#128#140#140#140#255#140 + +#140#140#255#164#164#164#255#187#187#187#255#179#179#179#255#172#172#172#255 + +#168#168#168#255#165#165#165#255#173#173#173#255#189#189#189#255#140#140#140 + +#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140#255#198#198#198#255 + +#198#198#198#255#140#140#140#255#178#178#178#0#178#178#178#128#178#178#178 + +#128#140#140#140#255#140#140#140#255#164#164#164#255#187#187#187#255#179#179 + +#179#255#173#173#173#255#178#178#178#255#192#192#192#255#140#140#140#255#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#140#140#140#255#204#204#204#255#204#204 + +#204#255#140#140#140#255#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + +#178#128#178#178#178#128#140#140#140#255#140#140#140#255#164#164#164#255#189 + +#189#189#255#190#190#190#255#203#203#203#255#140#140#140#255#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#140#140#140#255#216#216#216#255#216#216#216#255#140 + +#140#140#255#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + +#178#0#178#178#178#128#178#178#178#128#140#140#140#255#140#140#140#255#170 + +#170#170#255#173#173#173#255#140#140#140#255#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#140#140#140#255#140#140#140#255#140#140#140#255#140#140#140#255#178 + +#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#178#178#178#128#178#178#178#128#140#140#140#255#140#140 + +#140#255#178#178#178#128#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178#178#178 + +#128#178#178#178#128#178#178#178#128#178#178#178#128#178#178#178#0#178#178 + +#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0 + +#178#178#178#0#178#178#178#0#178#178#178#128#178#178#178#128#178#178#178#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + ,#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178 + +#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#140#140#140#255#140#140#140#255#140#140#140#255#178#178 + +#178#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#178#178#178#0#178#178#178#0#178 + +#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#178#178#178#0#140#140#140#255#140#140#140#255#187#187 + +#187#255#253#253#253#255#187#187#187#255#140#140#140#255#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0 + +#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#140#140#140#255#140 + +#140#140#255#185#185#185#255#248#248#248#255#247#247#247#255#247#247#247#255 + +#249#249#249#255#140#140#140#255#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178 + +#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + +#178#0#140#140#140#255#140#140#140#255#183#183#183#255#243#243#243#255#241 + +#241#241#255#240#240#240#255#239#239#239#255#241#241#241#255#244#244#244#255 + +#140#140#140#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#178#178#178#0#140#140#140#255#140#140#140#255#181#181 + +#181#255#237#237#237#255#235#235#235#255#234#234#234#255#233#233#233#255#232 + +#232#232#255#232#232#232#255#234#234#234#255#238#238#238#255#140#140#140#255 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#178#178#178#0#178#178#178#0#140#140 + +#140#255#140#140#140#255#179#179#179#255#232#232#232#255#230#230#230#255#228 + +#228#228#255#226#226#226#255#225#225#225#255#225#225#225#255#225#225#225#255 + +#225#225#225#255#228#228#228#255#233#233#233#255#140#140#140#255#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#178#178#178#0#140#140#140#255#179#179#179#255#228 + +#228#228#255#223#223#223#255#221#221#221#255#219#219#219#255#218#218#218#255 + +#217#217#217#255#217#217#217#255#217#217#217#255#217#217#217#255#217#217#217 + +#255#221#221#221#255#228#228#228#255#140#140#140#255#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#140#140#140#255#179#179#179#255#224#224#224#255#216#216#216 + +#255#212#212#212#255#211#211#211#255#210#210#210#255#210#210#210#255#210#210 + +#210#255#210#210#210#255#210#210#210#255#210#210#210#255#210#210#210#255#214 + +#214#214#255#222#222#222#255#140#140#140#255#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#140#140#140#255#171#171#171#255#192#192#192#255#176#176#176#255#169 + +#169#169#255#165#165#165#255#164#164#164#255#164#164#164#255#164#164#164#255 + +#164#164#164#255#164#164#164#255#164#164#164#255#164#164#164#255#172#172#172 + +#255#189#189#189#255#140#140#140#255#255#255#255#0#255#255#255#0#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178 + +#178#178#128#140#140#140#255#168#168#168#255#190#190#190#255#179#179#179#255 + +#172#172#172#255#168#168#168#255#165#165#165#255#164#164#164#255#164#164#164 + +#255#164#164#164#255#164#164#164#255#164#164#164#255#172#172#172#255#189#189 + +#189#255#140#140#140#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178#178#178#0 + +#178#178#178#128#140#140#140#255#140#140#140#255#164#164#164#255#187#187#187 + +#255#179#179#179#255#172#172#172#255#168#168#168#255#165#165#165#255#164#164 + +#164#255#164#164#164#255#164#164#164#255#172#172#172#255#189#189#189#255#140 + +#140#140#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178#178#178#0#178#178#178#0 + +#178#178#178#128#178#178#178#128#140#140#140#255#140#140#140#255#164#164#164 + +#255#187#187#187#255#179#179#179#255#172#172#172#255#168#168#168#255#165#165 + +#165#255#164#164#164#255#172#172#172#255#189#189#189#255#140#140#140#255#255 + ,#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#178#178#178#0#178#178#178#0#178#178#178#0 + +#178#178#178#0#178#178#178#128#178#178#178#128#140#140#140#255#140#140#140 + +#255#164#164#164#255#187#187#187#255#179#179#179#255#172#172#172#255#169#169 + +#169#255#175#175#175#255#191#191#191#255#140#140#140#255#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0 + +#178#178#178#0#178#178#178#0#178#178#178#128#178#178#178#128#140#140#140#255 + +#140#140#140#255#164#164#164#255#188#188#188#255#181#181#181#255#185#185#185 + +#255#200#200#200#255#140#140#140#255#255#255#255#0#255#255#255#0#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178 + +#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#178#178#178#0#178#178#178#128#178#178#178#128#140#140 + +#140#255#140#140#140#255#166#166#166#255#204#204#204#255#172#172#172#255#140 + +#140#140#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178#178#178#0#178#178#178#0 + +#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178 + +#178#178#0#178#178#178#0#178#178#178#0#178#178#178#128#178#178#178#128#140 + +#140#140#255#140#140#140#255#140#140#140#255#178#178#178#128#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0 + +#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#128#178#178#178#128 + +#178#178#178#128#178#178#178#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#178#178#178#0#140#140#140#255#140#140#140#255 + +#140#140#140#255#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178 + +#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#178#178#178#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#140 + +#140#140#255#187#187#187#255#253#253#253#255#187#187#187#255#140#140#140#255 + +#140#140#140#255#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178 + +#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + ,#178#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140#255#249#249#249#255 + +#247#247#247#255#247#247#247#255#248#248#248#255#185#185#185#255#140#140#140 + +#255#140#140#140#255#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0 + +#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#140#140#140#255#244#244#244#255#241#241#241#255#239#239 + +#239#255#240#240#240#255#241#241#241#255#243#243#243#255#183#183#183#255#140 + +#140#140#255#140#140#140#255#178#178#178#0#178#178#178#0#178#178#178#0#178 + +#178#178#0#178#178#178#0#178#178#178#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#140#140#140#255#238#238#238#255#234#234#234#255#232#232#232#255#232#232#232 + +#255#233#233#233#255#234#234#234#255#235#235#235#255#237#237#237#255#181#181 + +#181#255#140#140#140#255#140#140#140#255#178#178#178#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140#255#233 + +#233#233#255#228#228#228#255#225#225#225#255#225#225#225#255#225#225#225#255 + +#225#225#225#255#226#226#226#255#228#228#228#255#230#230#230#255#232#232#232 + +#255#179#179#179#255#140#140#140#255#140#140#140#255#178#178#178#0#178#178 + +#178#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140#255#228#228#228#255 + +#221#221#221#255#217#217#217#255#217#217#217#255#217#217#217#255#217#217#217 + +#255#217#217#217#255#218#218#218#255#219#219#219#255#221#221#221#255#223#223 + +#223#255#228#228#228#255#179#179#179#255#140#140#140#255#178#178#178#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#140#140#140#255#222#222#222#255#214#214 + +#214#255#210#210#210#255#210#210#210#255#210#210#210#255#210#210#210#255#210 + +#210#210#255#210#210#210#255#210#210#210#255#211#211#211#255#212#212#212#255 + +#216#216#216#255#224#224#224#255#179#179#179#255#140#140#140#255#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#140#140#140#255#189#189#189#255#172#172#172#255#164 + +#164#164#255#164#164#164#255#164#164#164#255#164#164#164#255#164#164#164#255 + +#164#164#164#255#164#164#164#255#165#165#165#255#169#169#169#255#176#176#176 + +#255#192#192#192#255#171#171#171#255#140#140#140#255#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#140#140#140#255#189#189#189#255#172#172#172#255#164#164#164 + +#255#164#164#164#255#164#164#164#255#164#164#164#255#164#164#164#255#165#165 + +#165#255#168#168#168#255#172#172#172#255#179#179#179#255#190#190#190#255#168 + +#168#168#255#140#140#140#255#178#178#178#128#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#140#140#140#255#189#189#189#255#172#172#172#255#164#164#164#255#164 + +#164#164#255#164#164#164#255#165#165#165#255#168#168#168#255#172#172#172#255 + +#179#179#179#255#187#187#187#255#164#164#164#255#140#140#140#255#140#140#140 + +#255#178#178#178#128#178#178#178#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#140 + +#140#140#255#189#189#189#255#172#172#172#255#164#164#164#255#165#165#165#255 + +#168#168#168#255#172#172#172#255#179#179#179#255#187#187#187#255#164#164#164 + +#255#140#140#140#255#140#140#140#255#178#178#178#128#178#178#178#128#178#178 + +#178#0#178#178#178#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140#255#191 + +#191#191#255#175#175#175#255#169#169#169#255#172#172#172#255#179#179#179#255 + +#187#187#187#255#164#164#164#255#140#140#140#255#140#140#140#255#178#178#178 + +#128#178#178#178#128#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#140#140#140#255#200#200#200#255#185 + +#185#185#255#181#181#181#255#188#188#188#255#164#164#164#255#140#140#140#255 + +#140#140#140#255#178#178#178#128#178#178#178#128#178#178#178#0#178#178#178#0 + +#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#140#140#140#255#172#172#172#255#204#204#204#255#166#166 + +#166#255#140#140#140#255#140#140#140#255#178#178#178#128#178#178#178#128#178 + +#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#178#178#178#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178 + ,#178#178#128#140#140#140#255#140#140#140#255#140#140#140#255#178#178#178#128 + +#178#178#178#128#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178 + +#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + +#178#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#178#178#178#0#178#178#178#128#178 + +#178#178#128#178#178#178#128#178#178#178#0#178#178#178#0#178#178#178#0#178 + +#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#178#178#178#0#178#178#178#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178#178#178#0#140#140#140 + +#255#140#140#140#255#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0 + +#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#140 + +#140#140#255#140#140#140#255#140#140#140#255#140#140#140#255#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#140#140#140#255#187#187#187#255#187#187#187#255#140 + +#140#140#255#140#140#140#255#178#178#178#0#178#178#178#0#178#178#178#0#178 + +#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#140#140#140#255#253#253 + +#253#255#253#253#253#255#140#140#140#255#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#140#140#140#255#249#249#249#255#248#248#248#255#248#248#248#255#185#185#185 + +#255#140#140#140#255#140#140#140#255#178#178#178#0#178#178#178#0#178#178#178 + +#0#178#178#178#0#178#178#178#0#140#140#140#255#249#249#249#255#249#249#249 + +#255#140#140#140#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140#255#244 + +#244#244#255#241#241#241#255#240#240#240#255#241#241#241#255#243#243#243#255 + +#183#183#183#255#140#140#140#255#140#140#140#255#178#178#178#0#178#178#178#0 + +#178#178#178#0#140#140#140#255#245#245#245#255#245#245#245#255#140#140#140 + +#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140#255#238#238#238#255 + +#234#234#234#255#232#232#232#255#233#233#233#255#234#234#234#255#235#235#235 + +#255#237#237#237#255#181#181#181#255#140#140#140#255#140#140#140#255#178#178 + +#178#0#140#140#140#255#240#240#240#255#240#240#240#255#140#140#140#255#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + ,#255#0#255#255#255#0#255#255#255#0#140#140#140#255#233#233#233#255#228#228 + +#228#255#225#225#225#255#225#225#225#255#225#225#225#255#226#226#226#255#228 + +#228#228#255#230#230#230#255#232#232#232#255#179#179#179#255#140#140#140#255 + +#140#140#140#255#236#236#236#255#236#236#236#255#140#140#140#255#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#140#140#140#255#228#228#228#255#221#221#221#255#217 + +#217#217#255#217#217#217#255#217#217#217#255#217#217#217#255#218#218#218#255 + +#219#219#219#255#221#221#221#255#223#223#223#255#228#228#228#255#140#140#140 + +#255#231#231#231#255#231#231#231#255#140#140#140#255#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#140#140#140#255#222#222#222#255#214#214#214#255#210#210#210 + +#255#210#210#210#255#210#210#210#255#210#210#210#255#210#210#210#255#210#210 + +#210#255#211#211#211#255#212#212#212#255#216#216#216#255#140#140#140#255#227 + +#227#227#255#227#227#227#255#140#140#140#255#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#140#140#140#255#189#189#189#255#172#172#172#255#164#164#164#255#164 + +#164#164#255#164#164#164#255#164#164#164#255#164#164#164#255#164#164#164#255 + +#165#165#165#255#169#169#169#255#176#176#176#255#140#140#140#255#198#198#198 + +#255#198#198#198#255#140#140#140#255#255#255#255#0#255#255#255#0#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#140 + +#140#140#255#189#189#189#255#172#172#172#255#164#164#164#255#164#164#164#255 + +#164#164#164#255#164#164#164#255#165#165#165#255#168#168#168#255#172#172#172 + +#255#179#179#179#255#190#190#190#255#140#140#140#255#198#198#198#255#198#198 + +#198#255#140#140#140#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140 + +#255#189#189#189#255#172#172#172#255#164#164#164#255#164#164#164#255#165#165 + +#165#255#168#168#168#255#172#172#172#255#179#179#179#255#187#187#187#255#164 + +#164#164#255#140#140#140#255#140#140#140#255#198#198#198#255#198#198#198#255 + +#140#140#140#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140#255#189#189 + +#189#255#173#173#173#255#165#165#165#255#168#168#168#255#172#172#172#255#179 + +#179#179#255#187#187#187#255#164#164#164#255#140#140#140#255#140#140#140#255 + +#178#178#178#128#140#140#140#255#198#198#198#255#198#198#198#255#140#140#140 + +#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#140#140#140#255#192#192#192#255 + +#178#178#178#255#173#173#173#255#179#179#179#255#187#187#187#255#164#164#164 + +#255#140#140#140#255#140#140#140#255#178#178#178#128#178#178#178#128#178#178 + +#178#0#140#140#140#255#198#198#198#255#198#198#198#255#140#140#140#255#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#140#140#140#255#203#203#203#255#190#190 + +#190#255#189#189#189#255#164#164#164#255#140#140#140#255#140#140#140#255#178 + +#178#178#128#178#178#178#128#178#178#178#0#178#178#178#0#178#178#178#0#140 + +#140#140#255#204#204#204#255#204#204#204#255#140#140#140#255#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#140#140#140#255#173#173#173#255#170#170#170#255#140 + +#140#140#255#140#140#140#255#178#178#178#128#178#178#178#128#178#178#178#0 + +#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#140#140#140#255#216 + +#216#216#255#216#216#216#255#140#140#140#255#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#178#178#178#128#140#140#140#255#140#140#140#255#178#178#178#128#178 + +#178#178#128#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#178#178#178#0#140#140#140#255#140#140#140#255#140#140 + +#140#255#140#140#140#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178#178#178#0 + +#178#178#178#128#178#178#178#128#178#178#178#0#178#178#178#0#178#178#178#0 + +#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178 + +#178#178#0#178#178#178#128#178#178#178#128#178#178#178#128#178#178#178#128 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + ,#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#202#202#202#0#202 + +#202#202#0#202#202#202#0#202#202#202#0#202#202#202#0#202#202#202#16#202#202 + +#202#235#206#206#206#251#206#206#206#251#205#205#205#251#205#205#205#251#206 + +#206#206#251#206#206#206#251#206#206#206#251#205#205#205#251#205#205#205#251 + +#206#206#206#251#203#203#203#235#202#202#202#16#202#202#202#0#202#202#202#0 + +#202#202#202#0#202#202#202#0#202#202#202#0#204#204#204#0#204#204#204#0#202 + +#202#202#0#201#201#201#0#201#201#201#0#200#200#200#16#208#208#208#239#226#226 + +#226#255#225#225#225#255#225#225#225#255#224#224#224#255#225#225#225#255#225 + +#225#225#255#225#225#225#255#225#225#225#255#225#225#225#255#226#226#226#255 + +#209#209#209#239#202#202#202#16#204#204#204#0#203#203#203#0#204#204#204#0#206 + +#206#206#0#206#206#206#0#186#186#186#0#185#185#185#0#199#199#199#0#205#205 + +#205#0#203#203#203#0#201#201#201#16#208#208#208#239#223#223#223#255#221#221 + +#221#255#221#221#221#255#222#222#222#255#222#222#222#255#222#222#222#255#222 + +#222#222#255#221#221#221#255#221#221#221#255#222#222#222#255#210#210#210#239 + +#204#204#204#16#205#205#205#0#208#208#208#0#202#202#202#0#189#189#189#0#189 + +#189#189#0#177#177#177#0#177#177#177#0#187#187#187#0#188#188#188#0#204#204 + +#204#0#203#203#203#16#208#208#208#239#220#220#220#255#220#220#220#255#219#219 + +#219#255#219#219#219#255#220#220#220#255#220#220#220#255#219#219#219#255#219 + +#219#219#255#220#220#220#255#220#220#220#255#211#211#211#239#208#208#208#16 + +#208#208#208#0#189#189#189#0#189#189#189#0#181#181#181#0#181#181#181#0#178 + +#178#178#0#178#178#178#0#188#188#188#0#178#178#178#0#187#187#187#0#205#205 + +#205#16#209#209#209#239#218#218#218#255#218#218#218#255#218#218#218#255#218 + +#218#218#255#217#217#217#255#218#218#218#255#218#218#218#255#217#217#217#255 + +#218#218#218#255#218#218#218#255#212#212#212#239#211#211#211#16#189#189#189#0 + +#177#177#177#0#190#190#190#0#182#182#182#0#182#182#182#0#178#178#178#0#178 + +#178#178#0#188#188#188#0#180#180#180#0#174#174#174#0#204#204#204#15#212#212 + +#212#239#216#216#216#255#216#216#216#255#215#215#215#255#216#216#216#255#216 + +#216#216#255#216#216#216#255#216#216#216#255#216#216#216#255#216#216#216#255 + +#216#216#216#255#211#211#211#239#187#187#187#13#175#175#175#0#180#180#180#0 + +#190#190#190#0#182#182#182#0#182#182#182#0#178#178#178#0#178#178#178#0#187 + +#187#187#0#179#179#179#27#178#178#178#16#163#163#163#16#202#202#202#237#216 + +#216#216#255#214#214#214#255#214#214#214#255#213#213#213#255#214#214#214#255 + +#214#214#214#255#213#213#213#255#214#214#214#255#214#214#214#255#215#215#215 + +#255#208#208#208#240#175#175#175'#'#178#178#178#16#179#179#179#13#189#189#189 + +#0#182#182#182#0#182#182#182#0#179#179#179#0#178#178#178#7#199#199#199#157 + +#180#180#180#243'yyy'#241#135#135#135#239#197#197#197#254#210#210#210#255#207 + +#207#207#255#207#207#207#255#207#207#207#255#207#207#207#255#207#207#207#255 + +#207#207#207#255#207#207#207#255#207#207#207#255#209#209#209#255#200#200#200 + +#254#138#138#138#242'ttt'#241#183#183#183#235#201#201#201#165#182#182#182#16 + +#183#183#183#0#190#190#190#0#187#187#187'Z'#241#241#241#254#211#211#211#255 + +#129#129#129#255#142#142#142#255#159#159#159#255#162#162#162#255#161#161#161 + +#255#161#161#161#255#161#161#161#255#161#161#161#255#161#161#161#255#161#161 + +#161#255#161#161#161#255#161#161#161#255#162#162#162#255#161#161#161#255'~~~' + +#255'nnn'#255#220#220#220#255#246#246#246#255#192#192#192'e'#195#195#195#0 + +#193#193#193#0#190#190#190'g'#247#247#247#255#202#202#202#255#133#133#133#255 + +#172#172#172#255#147#147#147#255#146#146#146#255#147#147#147#255#147#147#147 + +#255#146#146#146#255#146#146#146#255#146#146#146#255#147#147#147#255#147#147 + +#147#255#147#147#147#255#147#147#147#255#146#146#146#255#166#166#166#255#131 + +#131#131#255#215#215#215#255#250#250#250#255#197#197#197'q'#200#200#200#0#193 + +#193#193#0#190#190#190'm'#247#247#247#255#203#203#203#255#130#130#130#255#180 + +#180#180#255#175#175#175#255#176#176#176#255#175#175#175#255#175#175#175#255 + +#176#176#176#255#176#176#176#255#176#176#176#255#175#175#175#255#175#175#175 + +#255#175#175#175#255#176#176#176#255#176#176#176#255#181#181#181#255#130#130 + ,#130#255#214#214#214#255#250#250#250#255#196#196#196'v'#199#199#199#0#188#188 + +#188#0#185#185#185'p'#245#245#245#255#209#209#209#255'zzz'#255#129#129#129 + +#255'uuu'#255'www'#255'www'#255'www'#255'www'#255'www'#255'www'#255'www'#255 + +'www'#255'www'#255'www'#255'ttt'#255#131#131#131#255'{{{'#255#215#215#215#255 + +#248#248#248#255#189#189#189'v'#192#192#192#0#182#182#182#0#179#179#179'q' + +#235#235#235#255#210#210#210#255'ooo'#255'nnn'#255'ccc'#255'eee'#255'eee'#255 + +'eee'#255'eee'#255'eee'#255'eee'#255'eee'#255'eee'#255'eee'#255'eee'#255'ccc' + +#255'nnn'#255'mmm'#255#215#215#215#255#234#234#234#255#181#181#181'u'#184#184 + +#184#0#179#179#179#0#176#176#176't'#225#225#225#255#209#209#209#255'nnn'#255 + +#135#135#135#255#128#128#128#255#128#128#128#255#128#128#128#255#128#128#128 + +#255#128#128#128#255#128#128#128#255#128#128#128#255#128#128#128#255#128#128 + +#128#255#128#128#128#255#128#128#128#255#127#127#127#255#136#136#136#255'mmm' + +#255#211#211#211#255#222#222#222#255#176#176#176'v'#179#179#179#0#173#173#173 + +#0#170#170#170#127#212#212#212#255#234#234#234#255#150#150#150#255'jjj'#255 + +'qqq'#255'qqq'#255'qqq'#255'qqq'#255'ppp'#255'qqq'#255'qqq'#255'ppp'#255'qqq' + +#255'qqq'#255'qqq'#255'qqq'#255'iii'#255#160#160#160#255#238#238#238#255#207 + +#207#207#255#170#170#170#127#173#173#173#0#183#183#183#0#170#170#170#128#205 + +#205#205#255#224#224#224#255#234#234#234#255#229#229#229#255#237#237#237#255 + +#232#232#232#255#232#232#232#255#232#232#232#255#232#232#232#255#232#232#232 + +#255#232#232#232#255#232#232#232#255#231#231#231#255#231#231#231#255#231#231 + +#231#255#232#232#232#255#239#239#239#255#215#215#215#255#206#206#206#255#202 + +#202#202#255#170#170#170#128#183#183#183#0'ppp'#0#184#184#184#128#203#203#203 + +#255#216#216#216#255#214#214#214#255#205#205#205#255#147#147#147#255#173#173 + +#173#255#172#172#172#255#172#172#172#255#172#172#172#255#171#171#171#255#171 + +#171#171#255#171#171#171#255#171#171#171#255#171#171#171#255#171#171#171#255 + +#163#163#163#255#155#155#155#255#174#174#174#255#186#186#186#255#201#201#201 + +#255#184#184#184#128'ppp'#0#0#0#0#0'nnn'#130#212#212#212#255#212#212#212#255 + +#213#213#213#255#192#192#192#255'LLL'#255#150#150#150#255#148#148#148#255#149 + +#149#149#255#150#150#150#255#152#152#152#255#153#153#153#255#154#154#154#255 + +#155#155#155#255#158#158#158#255#161#161#161#255#141#141#141#255'WWW'#255#214 + +#214#214#255#209#209#209#255#208#208#208#255'nnn'#130#0#0#0#0#0#0#0#7'???F' + +#180#180#180#224#211#211#211#255#215#215#215#255#189#189#189#255'bbb'#255#192 + +#192#192#255#189#189#189#255#191#191#191#255#192#192#192#255#194#194#194#255 + +#196#196#196#255#198#198#198#255#199#199#199#255#202#202#202#255#206#206#206 + +#255#186#186#186#255'hhh'#255#214#214#214#255#210#210#210#255#184#184#184#233 + +'DDDR'#0#0#0#5#0#0#0#25#0#0#0'%>>>Qwww'#179'uuu'#182#135#135#135#185#142#142 + +#142#209#209#209#209#255#209#209#209#255#209#209#209#255#211#211#211#255#212 + +#212#212#255#214#214#214#255#216#216#216#255#217#217#217#255#218#218#218#255 + +#221#221#221#255#215#215#215#251'vvv'#194'ttt'#180'yyy'#180'CCCW'#0#0#0'$'#0 + +#0#0#25#0#0#0#4#0#0#0#5#0#0#0#0#0#0#0#0#0#0#0#0#17#17#17#0'\\\C'#225#225#225 + +#255#221#221#221#255#221#221#221#255#222#222#222#255#222#222#222#255#223#223 + +#223#255#225#225#225#255#225#225#225#255#226#226#226#255#228#228#228#255#224 + +#224#224#254'%%%'#12#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#5#0#0#0#4#0#0#0#0#0#0#0#0 + +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#15#3#3#3',%%%T$$$Z$$$Y$$$Y$$$Y$$$Y%%%Y%%%Y%%%' + +'Y%%%Z"""O'#0#0#0'"'#0#0#0#9#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + ,#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#178#178#178#0#178#178#178#0#131#131#131#255#131#131#131#255#178#178 + +#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0 + +#178#178#178#0#178#178#178#0#131#131#131#255#131#131#131#255#178#178#178#0 + +#178#178#178#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178#178#178#0#131#131 + +#131#255#182#182#182#255#182#182#182#255#131#131#131#255#178#178#178#0#178 + +#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#131#131 + +#131#255#182#182#182#255#182#182#182#255#131#131#131#255#178#178#178#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#131#131#131#255#181#181#181#255#249#249 + +#249#255#248#248#248#255#180#180#180#255#131#131#131#255#178#178#178#0#178 + +#178#178#0#178#178#178#0#178#178#178#0#131#131#131#255#180#180#180#255#248 + +#248#248#255#249#249#249#255#181#181#181#255#131#131#131#255#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#131#131#131#255#179#179#179#255#244#244#244#255#242 + +#242#242#255#243#243#243#255#178#178#178#255#131#131#131#255#178#178#178#0 + +#178#178#178#0#131#131#131#255#178#178#178#255#243#243#243#255#242#242#242 + +#255#244#244#244#255#179#179#179#255#131#131#131#255#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#178#178#178#128#131#131#131#255#177#177#177#255#237#237#237 + +#255#236#236#236#255#237#237#237#255#176#176#176#255#131#131#131#255#131#131 + +#131#255#176#176#176#255#237#237#237#255#236#236#236#255#237#237#237#255#177 + +#177#177#255#131#131#131#255#178#178#178#128#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#178#178#178#0#178#178#178#128#131#131#131#255#175#175#175#255#231#231 + +#231#255#229#229#229#255#229#229#229#255#229#229#229#255#229#229#229#255#229 + +#229#229#255#229#229#229#255#231#231#231#255#175#175#175#255#131#131#131#255 + +#178#178#178#128#178#178#178#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178#178 + +#178#0#178#178#178#0#178#178#178#128#131#131#131#255#171#171#171#255#223#223 + +#223#255#220#220#220#255#219#219#219#255#219#219#219#255#220#220#220#255#223 + +#223#223#255#171#171#171#255#131#131#131#255#178#178#178#128#178#178#178#0 + +#178#178#178#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#178#178#178#128#131#131#131#255#218#218#218#255#213#213 + +#213#255#211#211#211#255#211#211#211#255#213#213#213#255#218#218#218#255#131 + +#131#131#255#178#178#178#128#178#178#178#0#178#178#178#0#178#178#178#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#178#178#178#0#178#178#178#0#178#178#178#0 + +#178#178#178#0#131#131#131#255#184#184#184#255#175#175#175#255#171#171#171 + +#255#171#171#171#255#175#175#175#255#184#184#184#255#131#131#131#255#178#178 + +#178#0#178#178#178#0#178#178#178#0#178#178#178#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#178#178#178#0#178#178#178#0#178#178#178#0#131#131#131#255#158#158 + +#158#255#182#182#182#255#176#176#176#255#175#175#175#255#175#175#175#255#176 + +#176#176#255#182#182#182#255#158#158#158#255#131#131#131#255#178#178#178#0 + +#178#178#178#0#178#178#178#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178#178 + +#178#0#178#178#178#0#131#131#131#255#161#161#161#255#189#189#189#255#183#183 + +#183#255#182#182#182#255#184#184#184#255#184#184#184#255#182#182#182#255#183 + +#183#183#255#189#189#189#255#161#161#161#255#131#131#131#255#178#178#178#0 + +#178#178#178#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178#178#178#0#131#131 + +#131#255#162#162#162#255#191#191#191#255#186#186#186#255#189#189#189#255#158 + +#158#158#255#131#131#131#255#131#131#131#255#158#158#158#255#189#189#189#255 + +#186#186#186#255#191#191#191#255#162#162#162#255#131#131#131#255#178#178#178 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#131#131#131#255#167#167#167#255#198 + +#198#198#255#188#188#188#255#191#191#191#255#161#161#161#255#131#131#131#255 + +#178#178#178#128#178#178#178#128#131#131#131#255#161#161#161#255#191#191#191 + ,#255#188#188#188#255#198#198#198#255#167#167#167#255#131#131#131#255#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#131#131#131#255#168#168#168#255#203#203#203#255 + +#198#198#198#255#162#162#162#255#131#131#131#255#178#178#178#128#178#178#178 + +#0#178#178#178#0#178#178#178#128#131#131#131#255#162#162#162#255#198#198#198 + +#255#203#203#203#255#168#168#168#255#131#131#131#255#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#178#178#178#128#131#131#131#255#168#168#168#255#167#167#167 + +#255#131#131#131#255#178#178#178#128#178#178#178#0#178#178#178#0#178#178#178 + +#0#178#178#178#0#178#178#178#128#131#131#131#255#167#167#167#255#168#168#168 + +#255#131#131#131#255#178#178#178#128#255#255#255#0#255#255#255#0#255#255#255 + +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178 + +#178#178#0#178#178#178#128#131#131#131#255#131#131#131#255#178#178#178#128 + +#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178 + +#178#178#0#178#178#178#128#131#131#131#255#131#131#131#255#178#178#178#128 + +#178#178#178#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#178#178#178#0#178#178 + +#178#0#178#178#178#128#178#178#178#128#178#178#178#0#178#178#178#0#178#178 + +#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0#178#178#178#0 + +#178#178#178#128#178#178#178#128#178#178#178#0#178#178#178#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 + +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 + +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 + +#255#0#0#0#0 +]); diff --git a/components/kcontrols/source/kprintpreview.pas b/components/kcontrols/source/kprintpreview.pas new file mode 100755 index 000000000..b6cc0e0f9 --- /dev/null +++ b/components/kcontrols/source/kprintpreview.pas @@ -0,0 +1,228 @@ +{ @abstract(This unit contains print preview form.) + @author(Tomas Krysl (tk@tkweb.eu)) + @created(18 Sep 2009) + @lastmod(20 Jun 2010) + + Copyright © 2009 Tomas Krysl (tk@@tkweb.eu)

+ + License:
+ This code is distributed as a freeware. You are free to use it as part + of your application for any purpose including freeware, commercial and + shareware applications. The origin of this source code must not be + misrepresented; you must not claim your authorship. You may modify this code + solely for your own purpose. Please feel free to contact the author if you + think your changes might be useful for other users. You may distribute only + the original package. The author accepts no liability for any damage + that may result from using this code. } + +unit KPrintPreview; + +{$include kcontrols.inc} + +interface + +uses +{$IFDEF FPC} + LCLType, LCLIntf, LResources, +{$ELSE} + Windows, Messages, ToolWin, ImgList, +{$ENDIF} + SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, ComCtrls, ActnList, Buttons, StdCtrls, + ExtCtrls, KControls; + +type + + { TKPrintPreviewForm } + + TKPrintPreviewForm = class(TForm) + ILMain: TImageList; + ALMain: TActionList; + ACPageFirst: TAction; + ACPageLast: TAction; + ACPageNext: TAction; + ACPagePrevious: TAction; + ACClose: TAction; + ILMainDis: TImageList; + ToBMain: TToolBar; + TBPageFirst: TToolButton; + TBPagePrevious: TToolButton; + ToolButton1: TToolButton; + ToolButton3: TToolButton; + TBPageNext: TToolButton; + TBPageLast: TToolButton; + PNPage: TPanel; + EDPage: TEdit; + UDPage: TUpDown; + ToolButton6: TToolButton; + PNScale: TPanel; + CoBScale: TComboBox; + TBClose: TToolButton; + Preview: TKPrintPreview; + TBPrint: TToolButton; + ToolButton4: TToolButton; + ACPrint: TAction; + procedure CoBScaleExit(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure ACPageFirstExecute(Sender: TObject); + procedure ACPageFirstUpdate(Sender: TObject); + procedure ACPagePreviousExecute(Sender: TObject); + procedure ACPageNextExecute(Sender: TObject); + procedure ACPageNextUpdate(Sender: TObject); + procedure ACPageLastExecute(Sender: TObject); + procedure ACCloseExecute(Sender: TObject); + procedure ACCloseUpdate(Sender: TObject); + procedure EDPageExit(Sender: TObject); + procedure UDPageClick(Sender: TObject; Button: TUDBtnType); + procedure FormKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); + procedure PreviewChanged(Sender: TObject); + procedure ACPrintExecute(Sender: TObject); + procedure ACPrintUpdate(Sender: TObject); + procedure FormCreate(Sender: TObject); + private + procedure ScaleChanged; + { Private declarations } + public + { Public declarations } + end; + +implementation + +uses + KFunctions; + +procedure TKPrintPreviewForm.FormCreate(Sender: TObject); +begin + CoBScale.ItemIndex := 9; // page width + Preview.DoubleBuffered := True; +end; + +procedure TKPrintPreviewForm.FormShow(Sender: TObject); +begin + UDPage.Min := Preview.StartPage; + UDPage.Max := Preview.EndPage; +end; + +procedure TKPrintPreviewForm.CoBScaleExit(Sender: TObject); +begin + ScaleChanged; +end; + +procedure TKPrintPreviewForm.ACPageFirstExecute(Sender: TObject); +begin + Preview.FirstPage; +end; + +procedure TKPrintPreviewForm.ACPageFirstUpdate(Sender: TObject); +begin + TAction(Sender).Enabled := Preview.Page > Preview.StartPage; +end; + +procedure TKPrintPreviewForm.ACPagePreviousExecute(Sender: TObject); +begin + Preview.PreviousPage; +end; + +procedure TKPrintPreviewForm.ACPageNextExecute(Sender: TObject); +begin + Preview.NextPage; +end; + +procedure TKPrintPreviewForm.ACPageNextUpdate(Sender: TObject); +begin + TAction(Sender).Enabled := Preview.Page < Preview.EndPage; +end; + +procedure TKPrintPreviewForm.ACPageLastExecute(Sender: TObject); +begin + Preview.LastPage; +end; + +procedure TKPrintPreviewForm.ACPrintExecute(Sender: TObject); +begin + Preview.Control.PrintOut; +end; + +procedure TKPrintPreviewForm.ACPrintUpdate(Sender: TObject); +begin + TAction(Sender).Enabled := Assigned(Preview.Control) and Preview.Control.CanPrint; +end; + +procedure TKPrintPreviewForm.ACCloseExecute(Sender: TObject); +begin + Close; +end; + +procedure TKPrintPreviewForm.ACCloseUpdate(Sender: TObject); +begin + TAction(Sender).Enabled := True; +end; + +procedure TKPrintPreviewForm.EDPageExit(Sender: TObject); +begin + Preview.Page := MinMax(StrToIntDef(EDPage.Text, Preview.Page), Preview.StartPage, Preview.EndPage); + EDPage.Text := IntToStr(Preview.Page); +end; + +procedure TKPrintPreviewForm.UDPageClick(Sender: TObject; Button: TUDBtnType); +begin + EDPageExit(nil); +end; + +procedure TKPrintPreviewForm.FormKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + if Key = VK_ESCAPE then + begin + Close; + Key := 0; + end; +end; + +procedure TKPrintPreviewForm.PreviewChanged(Sender: TObject); +begin + EDPage.Text := IntToStr(Preview.Page); +end; + +procedure TKPrintPreviewForm.ScaleChanged; +var + S: string; +begin + S := CoBScale.Text; + if CoBScale.Items.IndexOf(S) < 0 then + CoBScale.ItemIndex := -1; + case CoBScale.ItemIndex of + -1: + begin + while (S <> '') and not CharInSetEx(S[Length(S)], ['0'..'9']) do Delete(S, Length(S), 1); + Preview.Scale := StrToIntDef(S, 100); + end; + 0: Preview.Scale := 25; + 1: Preview.Scale := 50; + 2: Preview.Scale := 75; + 3: Preview.Scale := 100; + 4: Preview.Scale := 125; + 5: Preview.Scale := 150; + 6: Preview.Scale := 200; + 7: Preview.Scale := 500; + end; + case CoBScale.ItemIndex of + -1: + begin + Preview.ScaleMode := smScale; + CobScale.Text := Format('%d %%', [Preview.Scale]); + end; + 0..7: Preview.ScaleMode := smScale; + 8: Preview.ScaleMode := smWholePage; + 9: Preview.ScaleMode := smPageWidth; + end; +end; + +{$IFDEF FPC} +initialization + {$i kprintpreview.lrs} +{$ELSE} + {$R *.dfm} +{$ENDIF} +end. diff --git a/components/kcontrols/source/kprintsetup.dfm b/components/kcontrols/source/kprintsetup.dfm new file mode 100755 index 000000000..049fca2c0 --- /dev/null +++ b/components/kcontrols/source/kprintsetup.dfm @@ -0,0 +1,427 @@ +object KPrintSetupForm: TKPrintSetupForm + Left = 808 + Top = 247 + ActiveControl = CBFitToPage + BorderStyle = bsDialog + Caption = 'Page setup' + ClientHeight = 357 + ClientWidth = 464 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = True + Position = poScreenCenter + OnCloseQuery = FormCloseQuery + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object GBFileToPrint: TGroupBox + Left = 8 + Top = 8 + Width = 449 + Height = 45 + Caption = 'Title of printed document:' + TabOrder = 0 + object EDTitle: TEdit + Left = 8 + Top = 16 + Width = 432 + Height = 21 + TabOrder = 0 + Text = 'EDTitle' + end + end + object GBPrintOptions: TGroupBox + Left = 8 + Top = 109 + Width = 249 + Height = 105 + Caption = 'Print options:' + TabOrder = 1 + object Label1: TLabel + Left = 162 + Top = 23 + Width = 29 + Height = 13 + Caption = 'Scale:' + Color = clBtnFace + FocusControl = EDPrintScale + ParentColor = False + end + object CBFitToPage: TCheckBox + Left = 8 + Top = 21 + Width = 70 + Height = 17 + Caption = '&Fit to page' + TabOrder = 0 + OnClick = EDTopExit + end + object CBPageNumbers: TCheckBox + Left = 8 + Top = 40 + Width = 86 + Height = 17 + Caption = 'Pa&ge numbers' + TabOrder = 1 + OnClick = CBPageNumbersClick + end + object CBUseColor: TCheckBox + Left = 8 + Top = 59 + Width = 62 + Height = 17 + Caption = '&Use color' + TabOrder = 2 + OnClick = CBPageNumbersClick + end + object EDPrintScale: TEdit + Left = 162 + Top = 39 + Width = 48 + Height = 21 + TabOrder = 3 + OnExit = EDTopExit + end + object CBPaintSelection: TCheckBox + Left = 8 + Top = 78 + Width = 87 + Height = 17 + Caption = 'Pa&int selection' + TabOrder = 4 + OnClick = CBPageNumbersClick + end + object CBPrintTitle: TCheckBox + Left = 134 + Top = 78 + Width = 61 + Height = 17 + Caption = 'Print tit&le' + TabOrder = 5 + OnClick = CBPageNumbersClick + end + end + object BUPrint: TButton + Left = 89 + Top = 325 + Width = 74 + Height = 25 + Caption = '&Print' + TabOrder = 4 + OnClick = BUPrintClick + end + object BUCancel: TButton + Left = 383 + Top = 325 + Width = 74 + Height = 25 + Cancel = True + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 5 + end + object GBMargins: TGroupBox + Left = 264 + Top = 109 + Width = 193 + Height = 211 + Caption = 'Margins:' + TabOrder = 3 + object LBMarginUnits: TLabel + Left = 8 + Top = 23 + Width = 62 + Height = 13 + Caption = 'Margin u&nits:' + Color = clBtnFace + FocusControl = CoBMarginUnits + ParentColor = False + end + object LBLeft: TLabel + Left = 8 + Top = 86 + Width = 23 + Height = 13 + Caption = 'Left:' + Color = clBtnFace + FocusControl = EDLeft + ParentColor = False + end + object LBRight: TLabel + Left = 102 + Top = 86 + Width = 29 + Height = 13 + Caption = 'Right:' + Color = clBtnFace + FocusControl = EDRight + ParentColor = False + end + object LBTop: TLabel + Left = 9 + Top = 131 + Width = 22 + Height = 13 + Caption = 'Top:' + Color = clBtnFace + FocusControl = EDTop + ParentColor = False + end + object LBBottom: TLabel + Left = 102 + Top = 131 + Width = 38 + Height = 13 + Caption = 'Bottom:' + Color = clBtnFace + FocusControl = EDBottom + ParentColor = False + end + object LBUnitsLeft: TLabel + Left = 58 + Top = 105 + Width = 7 + Height = 13 + Caption = 'A' + Color = clBtnFace + ParentColor = False + end + object LBUnitsTop: TLabel + Left = 58 + Top = 150 + Width = 7 + Height = 13 + Caption = 'A' + Color = clBtnFace + ParentColor = False + end + object LBUnitsRight: TLabel + Left = 152 + Top = 105 + Width = 7 + Height = 13 + Caption = 'A' + Color = clBtnFace + ParentColor = False + end + object LBUnitsBottom: TLabel + Left = 152 + Top = 150 + Width = 7 + Height = 13 + Caption = 'A' + Color = clBtnFace + ParentColor = False + end + object CoBMarginUnits: TComboBox + Left = 8 + Top = 39 + Width = 176 + Height = 21 + Style = csDropDownList + ItemHeight = 13 + TabOrder = 0 + OnChange = CoBMarginUnitsChange + Items.Strings = ( + 'milimeters' + 'centimeters' + 'inches' + 'hundredths of inches') + end + object CBMirrorMargins: TCheckBox + Left = 8 + Top = 181 + Width = 86 + Height = 17 + Caption = '&Mirror margins' + TabOrder = 5 + OnClick = CBPageNumbersClick + end + object EDLeft: TEdit + Left = 8 + Top = 102 + Width = 48 + Height = 21 + TabOrder = 1 + OnExit = EDTopExit + end + object EDRight: TEdit + Left = 102 + Top = 102 + Width = 48 + Height = 21 + TabOrder = 2 + OnExit = EDTopExit + end + object EDTop: TEdit + Left = 8 + Top = 147 + Width = 48 + Height = 21 + TabOrder = 3 + OnExit = EDTopExit + end + object EDBottom: TEdit + Left = 102 + Top = 147 + Width = 48 + Height = 21 + TabOrder = 4 + OnExit = EDTopExit + end + end + object GBPageSelection: TGroupBox + Left = 8 + Top = 215 + Width = 249 + Height = 105 + Caption = 'Page selection:' + TabOrder = 2 + object LBRangeTo: TLabel + Left = 163 + Top = 51 + Width = 14 + Height = 13 + Caption = 'to:' + Color = clBtnFace + ParentColor = False + end + object LBCopies: TLabel + Left = 8 + Top = 78 + Width = 87 + Height = 13 + Caption = 'Number of &copies:' + Color = clBtnFace + FocusControl = EDCopies + ParentColor = False + end + object RBAll: TRadioButton + Left = 8 + Top = 22 + Width = 61 + Height = 17 + Caption = '&All pages' + Checked = True + TabOrder = 0 + TabStop = True + OnClick = RBAllClick + end + object RBRange: TRadioButton + Left = 8 + Top = 48 + Width = 78 + Height = 17 + Caption = '&Range from:' + TabOrder = 1 + OnClick = RBAllClick + end + object RBSelectedOnly: TRadioButton + Left = 128 + Top = 22 + Width = 82 + Height = 17 + Caption = 'Selected &only' + TabOrder = 2 + OnClick = RBAllClick + end + object EDRangeFrom: TEdit + Left = 108 + Top = 46 + Width = 48 + Height = 21 + TabOrder = 3 + OnExit = EDTopExit + end + object EDRangeTo: TEdit + Left = 193 + Top = 46 + Width = 48 + Height = 21 + TabOrder = 4 + OnExit = EDTopExit + end + object EDCopies: TEdit + Left = 126 + Top = 73 + Width = 48 + Height = 21 + TabOrder = 5 + end + object CBCollate: TCheckBox + Left = 179 + Top = 75 + Width = 51 + Height = 17 + Caption = 'Collate' + TabOrder = 6 + OnClick = CBPageNumbersClick + end + end + object BUPreview: TButton + Left = 8 + Top = 325 + Width = 75 + Height = 25 + Caption = 'Previe&w...' + TabOrder = 6 + OnClick = BUPreviewClick + end + object BUOk: TButton + Left = 303 + Top = 325 + Width = 74 + Height = 25 + Caption = 'OK' + Default = True + ModalResult = 1 + TabOrder = 7 + end + object GBPrinter: TGroupBox + Left = 8 + Top = 56 + Width = 449 + Height = 50 + Caption = 'Printer settings' + TabOrder = 8 + object LBPrinterName: TLabel + Left = 8 + Top = 20 + Width = 65 + Height = 13 + Caption = 'Printer name:' + Color = clBtnFace + FocusControl = EDCopies + ParentColor = False + end + object CoBPrinterName: TComboBox + Left = 112 + Top = 17 + Width = 206 + Height = 21 + ItemHeight = 13 + TabOrder = 0 + Text = 'CoBPrinterName' + OnChange = EDTopExit + end + object BUConfigure: TButton + Left = 328 + Top = 15 + Width = 113 + Height = 25 + Caption = 'Configure...' + TabOrder = 1 + OnClick = BUConfigureClick + end + end + object PSDMain: TPrinterSetupDialog + Left = 416 + Top = 29 + end +end diff --git a/components/kcontrols/source/kprintsetup.lfm b/components/kcontrols/source/kprintsetup.lfm new file mode 100755 index 000000000..26f0b5b3b --- /dev/null +++ b/components/kcontrols/source/kprintsetup.lfm @@ -0,0 +1,423 @@ +object KPrintSetupForm: TKPrintSetupForm + Left = 838 + Height = 357 + Top = 417 + Width = 464 + ActiveControl = EDTitle + BorderStyle = bsDialog + Caption = 'Page setup' + ClientHeight = 357 + ClientWidth = 464 + Font.Height = -11 + Font.Name = 'Tahoma' + OnCloseQuery = FormCloseQuery + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + Position = poScreenCenter + LCLVersion = '0.9.29' + object GBFileToPrint: TGroupBox + Left = 8 + Height = 45 + Top = 8 + Width = 449 + Caption = 'Title of printed document:' + ClientHeight = 27 + ClientWidth = 445 + TabOrder = 0 + object EDTitle: TEdit + Left = 8 + Height = 21 + Top = 2 + Width = 432 + TabOrder = 0 + Text = 'EDTitle' + end + end + object GBPrintOptions: TGroupBox + Left = 8 + Height = 105 + Top = 109 + Width = 249 + Caption = 'Print options:' + ClientHeight = 87 + ClientWidth = 245 + TabOrder = 1 + object Label1: TLabel + Left = 162 + Height = 14 + Top = 4 + Width = 30 + Caption = 'Scale:' + FocusControl = EDPrintScale + ParentColor = False + end + object CBFitToPage: TCheckBox + Left = 8 + Height = 17 + Top = 2 + Width = 70 + Caption = '&Fit to page' + OnClick = EDTopExit + TabOrder = 0 + end + object CBPageNumbers: TCheckBox + Left = 8 + Height = 17 + Top = 21 + Width = 86 + Caption = 'Pa&ge numbers' + OnClick = CBPageNumbersClick + TabOrder = 1 + end + object CBUseColor: TCheckBox + Left = 8 + Height = 17 + Top = 40 + Width = 62 + Caption = '&Use color' + OnClick = CBPageNumbersClick + TabOrder = 2 + end + object EDPrintScale: TEdit + Left = 162 + Height = 21 + Top = 20 + Width = 48 + OnExit = EDTopExit + TabOrder = 3 + end + object CBPaintSelection: TCheckBox + Left = 8 + Height = 17 + Top = 59 + Width = 87 + Caption = 'Pa&int selection' + OnClick = CBPageNumbersClick + TabOrder = 4 + end + object CBPrintTitle: TCheckBox + Left = 134 + Height = 17 + Top = 59 + Width = 61 + Caption = 'Print tit&le' + OnClick = CBPageNumbersClick + TabOrder = 5 + end + end + object BUPrint: TButton + Left = 89 + Height = 25 + Top = 325 + Width = 74 + Caption = '&Print' + OnClick = BUPrintClick + TabOrder = 4 + end + object BUCancel: TButton + Left = 383 + Height = 25 + Top = 325 + Width = 74 + Cancel = True + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 5 + end + object GBMargins: TGroupBox + Left = 264 + Height = 211 + Top = 109 + Width = 193 + Caption = 'Margins:' + ClientHeight = 193 + ClientWidth = 189 + TabOrder = 3 + object LBMarginUnits: TLabel + Left = 8 + Height = 14 + Top = 6 + Width = 63 + Caption = 'Margin u&nits:' + FocusControl = CoBMarginUnits + ParentColor = False + end + object LBLeft: TLabel + Left = 8 + Height = 14 + Top = 67 + Width = 24 + Caption = 'Left:' + FocusControl = EDLeft + ParentColor = False + end + object LBRight: TLabel + Left = 102 + Height = 14 + Top = 67 + Width = 30 + Caption = 'Right:' + FocusControl = EDRight + ParentColor = False + end + object LBTop: TLabel + Left = 9 + Height = 14 + Top = 126 + Width = 23 + Caption = 'Top:' + FocusControl = EDTop + ParentColor = False + end + object LBBottom: TLabel + Left = 102 + Height = 14 + Top = 112 + Width = 39 + Caption = 'Bottom:' + FocusControl = EDBottom + ParentColor = False + end + object LBUnitsLeft: TLabel + Left = 58 + Height = 14 + Top = 86 + Width = 8 + Caption = 'A' + ParentColor = False + end + object LBUnitsTop: TLabel + Left = 58 + Height = 14 + Top = 131 + Width = 8 + Caption = 'A' + ParentColor = False + end + object LBUnitsRight: TLabel + Left = 152 + Height = 14 + Top = 86 + Width = 8 + Caption = 'A' + ParentColor = False + end + object LBUnitsBottom: TLabel + Left = 152 + Height = 14 + Top = 131 + Width = 8 + Caption = 'A' + ParentColor = False + end + object CoBMarginUnits: TComboBox + Left = 8 + Height = 21 + Top = 22 + Width = 176 + ItemHeight = 13 + Items.Strings = ( + 'milimeters' + 'centimeters' + 'inches' + 'hundredths of inches' + ) + OnChange = CoBMarginUnitsChange + Style = csDropDownList + TabOrder = 0 + end + object CBMirrorMargins: TCheckBox + Left = 8 + Height = 17 + Top = 162 + Width = 86 + Caption = '&Mirror margins' + OnClick = CBPageNumbersClick + TabOrder = 5 + end + object EDLeft: TEdit + Left = 8 + Height = 21 + Top = 83 + Width = 48 + OnExit = EDTopExit + TabOrder = 1 + end + object EDRight: TEdit + Left = 102 + Height = 21 + Top = 83 + Width = 48 + OnExit = EDTopExit + TabOrder = 2 + end + object EDTop: TEdit + Left = 8 + Height = 21 + Top = 128 + Width = 48 + OnExit = EDTopExit + TabOrder = 3 + end + object EDBottom: TEdit + Left = 102 + Height = 21 + Top = 128 + Width = 48 + OnExit = EDTopExit + TabOrder = 4 + end + end + object GBPageSelection: TGroupBox + Left = 8 + Height = 105 + Top = 215 + Width = 249 + Caption = 'Page selection:' + ClientHeight = 87 + ClientWidth = 245 + TabOrder = 2 + object LBRangeTo: TLabel + Left = 163 + Height = 14 + Top = 32 + Width = 15 + Caption = 'to:' + ParentColor = False + end + object LBCopies: TLabel + Left = 8 + Height = 14 + Top = 59 + Width = 88 + Caption = 'Number of &copies:' + FocusControl = EDCopies + ParentColor = False + end + object RBAll: TRadioButton + Left = 8 + Height = 17 + Top = 3 + Width = 61 + Caption = '&All pages' + Checked = True + OnClick = RBAllClick + State = cbChecked + TabOrder = 0 + end + object RBRange: TRadioButton + Left = 8 + Height = 17 + Top = 29 + Width = 78 + Caption = '&Range from:' + OnClick = RBAllClick + TabOrder = 1 + TabStop = False + end + object RBSelectedOnly: TRadioButton + Left = 128 + Height = 17 + Top = 3 + Width = 82 + Caption = 'Selected &only' + OnClick = RBAllClick + TabOrder = 2 + TabStop = False + end + object EDRangeFrom: TEdit + Left = 108 + Height = 21 + Top = 27 + Width = 48 + OnExit = EDTopExit + TabOrder = 3 + end + object EDRangeTo: TEdit + Left = 193 + Height = 21 + Top = 27 + Width = 48 + OnExit = EDTopExit + TabOrder = 4 + end + object EDCopies: TEdit + Left = 126 + Height = 21 + Top = 54 + Width = 48 + TabOrder = 5 + end + object CBCollate: TCheckBox + Left = 179 + Height = 17 + Top = 56 + Width = 51 + Caption = 'Collate' + OnClick = CBPageNumbersClick + TabOrder = 6 + end + end + object BUPreview: TButton + Left = 8 + Height = 25 + Top = 325 + Width = 75 + Caption = 'Previe&w...' + OnClick = BUPreviewClick + TabOrder = 6 + end + object BUOk: TButton + Left = 303 + Height = 25 + Top = 325 + Width = 74 + Caption = 'OK' + Default = True + ModalResult = 1 + TabOrder = 7 + end + object GBPrinter: TGroupBox + Left = 8 + Height = 50 + Top = 56 + Width = 449 + Caption = 'Printer settings' + ClientHeight = 32 + ClientWidth = 445 + TabOrder = 8 + object LBPrinterName: TLabel + Left = 8 + Height = 14 + Top = 6 + Width = 66 + Caption = 'Printer name:' + FocusControl = EDCopies + ParentColor = False + end + object CoBPrinterName: TComboBox + Left = 112 + Height = 21 + Top = 2 + Width = 206 + ItemHeight = 13 + OnChange = EDTopExit + TabOrder = 0 + Text = 'CoBPrinterName' + end + object BUConfigure: TButton + Left = 328 + Height = 25 + Top = 1 + Width = 113 + Caption = 'Configure...' + OnClick = BUConfigureClick + TabOrder = 1 + end + end + object PSDMain: TPrinterSetupDialog + left = 376 + top = 104 + end +end diff --git a/components/kcontrols/source/kprintsetup.lrs b/components/kcontrols/source/kprintsetup.lrs new file mode 100755 index 000000000..203e0c02f --- /dev/null +++ b/components/kcontrols/source/kprintsetup.lrs @@ -0,0 +1,102 @@ +{ This is an automatically generated lazarus resource file } + +LazarusResources.Add('TKPrintSetupForm','FORMDATA',[ + 'TPF0'#16'TKPrintSetupForm'#15'KPrintSetupForm'#4'Left'#3'F'#3#6'Height'#3'e' + +#1#3'Top'#3#161#1#5'Width'#3#208#1#13'ActiveControl'#7#7'EDTitle'#11'BorderS' + +'tyle'#7#8'bsDialog'#7'Caption'#6#10'Page setup'#12'ClientHeight'#3'e'#1#11 + +'ClientWidth'#3#208#1#11'Font.Height'#2#245#9'Font.Name'#6#6'Tahoma'#12'OnCl' + +'oseQuery'#7#14'FormCloseQuery'#8'OnCreate'#7#10'FormCreate'#9'OnDestroy'#7 + +#11'FormDestroy'#6'OnShow'#7#8'FormShow'#8'Position'#7#14'poScreenCenter'#10 + +'LCLVersion'#6#6'0.9.29'#0#9'TGroupBox'#13'GBFileToPrint'#4'Left'#2#8#6'Heig' + +'ht'#2'-'#3'Top'#2#8#5'Width'#3#193#1#7'Caption'#6#26'Title of printed docum' + +'ent:'#12'ClientHeight'#2#27#11'ClientWidth'#3#189#1#8'TabOrder'#2#0#0#5'TEd' + +'it'#7'EDTitle'#4'Left'#2#8#6'Height'#2#21#3'Top'#2#2#5'Width'#3#176#1#8'Tab' + +'Order'#2#0#4'Text'#6#7'EDTitle'#0#0#0#9'TGroupBox'#14'GBPrintOptions'#4'Lef' + +'t'#2#8#6'Height'#2'i'#3'Top'#2'm'#5'Width'#3#249#0#7'Caption'#6#14'Print op' + +'tions:'#12'ClientHeight'#2'W'#11'ClientWidth'#3#245#0#8'TabOrder'#2#1#0#6'T' + +'Label'#6'Label1'#4'Left'#3#162#0#6'Height'#2#14#3'Top'#2#4#5'Width'#2#30#7 + +'Caption'#6#6'Scale:'#12'FocusControl'#7#12'EDPrintScale'#11'ParentColor'#8#0 + +#0#9'TCheckBox'#11'CBFitToPage'#4'Left'#2#8#6'Height'#2#17#3'Top'#2#2#5'Widt' + +'h'#2'F'#7'Caption'#6#12'&Fit to page'#7'OnClick'#7#9'EDTopExit'#8'TabOrder' + +#2#0#0#0#9'TCheckBox'#13'CBPageNumbers'#4'Left'#2#8#6'Height'#2#17#3'Top'#2 + +#21#5'Width'#2'V'#7'Caption'#6#13'Pa&ge numbers'#7'OnClick'#7#18'CBPageNumbe' + +'rsClick'#8'TabOrder'#2#1#0#0#9'TCheckBox'#10'CBUseColor'#4'Left'#2#8#6'Heig' + +'ht'#2#17#3'Top'#2'('#5'Width'#2'>'#7'Caption'#6#10'&Use color'#7'OnClick'#7 + +#18'CBPageNumbersClick'#8'TabOrder'#2#2#0#0#5'TEdit'#12'EDPrintScale'#4'Left' + +#3#162#0#6'Height'#2#21#3'Top'#2#20#5'Width'#2'0'#6'OnExit'#7#9'EDTopExit'#8 + +'TabOrder'#2#3#0#0#9'TCheckBox'#16'CBPaintSelection'#4'Left'#2#8#6'Height'#2 + +#17#3'Top'#2';'#5'Width'#2'W'#7'Caption'#6#16'Pa&int selection'#7'OnClick'#7 + +#18'CBPageNumbersClick'#8'TabOrder'#2#4#0#0#9'TCheckBox'#12'CBPrintTitle'#4 + +'Left'#3#134#0#6'Height'#2#17#3'Top'#2';'#5'Width'#2'='#7'Caption'#6#12'Prin' + +'t tit&le'#7'OnClick'#7#18'CBPageNumbersClick'#8'TabOrder'#2#5#0#0#0#7'TButt' + +'on'#7'BUPrint'#4'Left'#2'Y'#6'Height'#2#25#3'Top'#3'E'#1#5'Width'#2'J'#7'Ca' + +'ption'#6#6'&Print'#7'OnClick'#7#12'BUPrintClick'#8'TabOrder'#2#4#0#0#7'TBut' + +'ton'#8'BUCancel'#4'Left'#3#127#1#6'Height'#2#25#3'Top'#3'E'#1#5'Width'#2'J' + +#6'Cancel'#9#7'Caption'#6#6'Cancel'#11'ModalResult'#2#2#8'TabOrder'#2#5#0#0#9 + +'TGroupBox'#9'GBMargins'#4'Left'#3#8#1#6'Height'#3#211#0#3'Top'#2'm'#5'Width' + +#3#193#0#7'Caption'#6#8'Margins:'#12'ClientHeight'#3#193#0#11'ClientWidth'#3 + +#189#0#8'TabOrder'#2#3#0#6'TLabel'#13'LBMarginUnits'#4'Left'#2#8#6'Height'#2 + +#14#3'Top'#2#6#5'Width'#2'?'#7'Caption'#6#14'Margin u&nits:'#12'FocusControl' + +#7#14'CoBMarginUnits'#11'ParentColor'#8#0#0#6'TLabel'#6'LBLeft'#4'Left'#2#8#6 + +'Height'#2#14#3'Top'#2'C'#5'Width'#2#24#7'Caption'#6#5'Left:'#12'FocusContro' + +'l'#7#6'EDLeft'#11'ParentColor'#8#0#0#6'TLabel'#7'LBRight'#4'Left'#2'f'#6'He' + +'ight'#2#14#3'Top'#2'C'#5'Width'#2#30#7'Caption'#6#6'Right:'#12'FocusControl' + +#7#7'EDRight'#11'ParentColor'#8#0#0#6'TLabel'#5'LBTop'#4'Left'#2#9#6'Height' + +#2#14#3'Top'#2'~'#5'Width'#2#23#7'Caption'#6#4'Top:'#12'FocusControl'#7#5'ED' + +'Top'#11'ParentColor'#8#0#0#6'TLabel'#8'LBBottom'#4'Left'#2'f'#6'Height'#2#14 + +#3'Top'#2'p'#5'Width'#2''''#7'Caption'#6#7'Bottom:'#12'FocusControl'#7#8'EDB' + +'ottom'#11'ParentColor'#8#0#0#6'TLabel'#11'LBUnitsLeft'#4'Left'#2':'#6'Heigh' + +'t'#2#14#3'Top'#2'V'#5'Width'#2#8#7'Caption'#6#1'A'#11'ParentColor'#8#0#0#6 + +'TLabel'#10'LBUnitsTop'#4'Left'#2':'#6'Height'#2#14#3'Top'#3#131#0#5'Width'#2 + +#8#7'Caption'#6#1'A'#11'ParentColor'#8#0#0#6'TLabel'#12'LBUnitsRight'#4'Left' + +#3#152#0#6'Height'#2#14#3'Top'#2'V'#5'Width'#2#8#7'Caption'#6#1'A'#11'Parent' + +'Color'#8#0#0#6'TLabel'#13'LBUnitsBottom'#4'Left'#3#152#0#6'Height'#2#14#3'T' + +'op'#3#131#0#5'Width'#2#8#7'Caption'#6#1'A'#11'ParentColor'#8#0#0#9'TComboBo' + +'x'#14'CoBMarginUnits'#4'Left'#2#8#6'Height'#2#21#3'Top'#2#22#5'Width'#3#176 + +#0#10'ItemHeight'#2#13#13'Items.Strings'#1#6#10'milimeters'#6#11'centimeters' + +#6#6'inches'#6#20'hundredths of inches'#0#8'OnChange'#7#20'CoBMarginUnitsCha' + +'nge'#5'Style'#7#14'csDropDownList'#8'TabOrder'#2#0#0#0#9'TCheckBox'#15'CBMi' + +'rrorMargins'#4'Left'#2#8#6'Height'#2#17#3'Top'#3#162#0#5'Width'#2'V'#7'Capt' + +'ion'#6#15'&Mirror margins'#7'OnClick'#7#18'CBPageNumbersClick'#8'TabOrder'#2 + +#5#0#0#5'TEdit'#6'EDLeft'#4'Left'#2#8#6'Height'#2#21#3'Top'#2'S'#5'Width'#2 + +'0'#6'OnExit'#7#9'EDTopExit'#8'TabOrder'#2#1#0#0#5'TEdit'#7'EDRight'#4'Left' + +#2'f'#6'Height'#2#21#3'Top'#2'S'#5'Width'#2'0'#6'OnExit'#7#9'EDTopExit'#8'Ta' + +'bOrder'#2#2#0#0#5'TEdit'#5'EDTop'#4'Left'#2#8#6'Height'#2#21#3'Top'#3#128#0 + +#5'Width'#2'0'#6'OnExit'#7#9'EDTopExit'#8'TabOrder'#2#3#0#0#5'TEdit'#8'EDBot' + +'tom'#4'Left'#2'f'#6'Height'#2#21#3'Top'#3#128#0#5'Width'#2'0'#6'OnExit'#7#9 + +'EDTopExit'#8'TabOrder'#2#4#0#0#0#9'TGroupBox'#15'GBPageSelection'#4'Left'#2 + ,#8#6'Height'#2'i'#3'Top'#3#215#0#5'Width'#3#249#0#7'Caption'#6#15'Page selec' + +'tion:'#12'ClientHeight'#2'W'#11'ClientWidth'#3#245#0#8'TabOrder'#2#2#0#6'TL' + +'abel'#9'LBRangeTo'#4'Left'#3#163#0#6'Height'#2#14#3'Top'#2' '#5'Width'#2#15 + +#7'Caption'#6#3'to:'#11'ParentColor'#8#0#0#6'TLabel'#8'LBCopies'#4'Left'#2#8 + +#6'Height'#2#14#3'Top'#2';'#5'Width'#2'X'#7'Caption'#6#18'Number of &copies:' + +#12'FocusControl'#7#8'EDCopies'#11'ParentColor'#8#0#0#12'TRadioButton'#5'RBA' + +'ll'#4'Left'#2#8#6'Height'#2#17#3'Top'#2#3#5'Width'#2'='#7'Caption'#6#10'&Al' + +'l pages'#7'Checked'#9#7'OnClick'#7#10'RBAllClick'#5'State'#7#9'cbChecked'#8 + +'TabOrder'#2#0#0#0#12'TRadioButton'#7'RBRange'#4'Left'#2#8#6'Height'#2#17#3 + +'Top'#2#29#5'Width'#2'N'#7'Caption'#6#12'&Range from:'#7'OnClick'#7#10'RBAll' + +'Click'#8'TabOrder'#2#1#7'TabStop'#8#0#0#12'TRadioButton'#14'RBSelectedOnly' + +#4'Left'#3#128#0#6'Height'#2#17#3'Top'#2#3#5'Width'#2'R'#7'Caption'#6#14'Sel' + +'ected &only'#7'OnClick'#7#10'RBAllClick'#8'TabOrder'#2#2#7'TabStop'#8#0#0#5 + +'TEdit'#11'EDRangeFrom'#4'Left'#2'l'#6'Height'#2#21#3'Top'#2#27#5'Width'#2'0' + +#6'OnExit'#7#9'EDTopExit'#8'TabOrder'#2#3#0#0#5'TEdit'#9'EDRangeTo'#4'Left'#3 + +#193#0#6'Height'#2#21#3'Top'#2#27#5'Width'#2'0'#6'OnExit'#7#9'EDTopExit'#8'T' + +'abOrder'#2#4#0#0#5'TEdit'#8'EDCopies'#4'Left'#2'~'#6'Height'#2#21#3'Top'#2 + +'6'#5'Width'#2'0'#8'TabOrder'#2#5#0#0#9'TCheckBox'#9'CBCollate'#4'Left'#3#179 + +#0#6'Height'#2#17#3'Top'#2'8'#5'Width'#2'3'#7'Caption'#6#7'Collate'#7'OnClic' + +'k'#7#18'CBPageNumbersClick'#8'TabOrder'#2#6#0#0#0#7'TButton'#9'BUPreview'#4 + +'Left'#2#8#6'Height'#2#25#3'Top'#3'E'#1#5'Width'#2'K'#7'Caption'#6#11'Previe' + +'&w...'#7'OnClick'#7#14'BUPreviewClick'#8'TabOrder'#2#6#0#0#7'TButton'#4'BUO' + +'k'#4'Left'#3'/'#1#6'Height'#2#25#3'Top'#3'E'#1#5'Width'#2'J'#7'Caption'#6#2 + +'OK'#7'Default'#9#11'ModalResult'#2#1#8'TabOrder'#2#7#0#0#9'TGroupBox'#9'GBP' + +'rinter'#4'Left'#2#8#6'Height'#2'2'#3'Top'#2'8'#5'Width'#3#193#1#7'Caption'#6 + +#16'Printer settings'#12'ClientHeight'#2' '#11'ClientWidth'#3#189#1#8'TabOrd' + +'er'#2#8#0#6'TLabel'#13'LBPrinterName'#4'Left'#2#8#6'Height'#2#14#3'Top'#2#6 + +#5'Width'#2'B'#7'Caption'#6#13'Printer name:'#12'FocusControl'#7#8'EDCopies' + +#11'ParentColor'#8#0#0#9'TComboBox'#14'CoBPrinterName'#4'Left'#2'p'#6'Height' + +#2#21#3'Top'#2#2#5'Width'#3#206#0#10'ItemHeight'#2#13#8'OnChange'#7#9'EDTopE' + +'xit'#8'TabOrder'#2#0#4'Text'#6#14'CoBPrinterName'#0#0#7'TButton'#11'BUConfi' + +'gure'#4'Left'#3'H'#1#6'Height'#2#25#3'Top'#2#1#5'Width'#2'q'#7'Caption'#6#12 + +'Configure...'#7'OnClick'#7#16'BUConfigureClick'#8'TabOrder'#2#1#0#0#0#19'TP' + +'rinterSetupDialog'#7'PSDMain'#4'left'#3'x'#1#3'top'#2'h'#0#0#0 +]); diff --git a/components/kcontrols/source/kprintsetup.pas b/components/kcontrols/source/kprintsetup.pas new file mode 100755 index 000000000..6e9d8eadd --- /dev/null +++ b/components/kcontrols/source/kprintsetup.pas @@ -0,0 +1,369 @@ +{ @abstract(This unit contains page setup dialog.) + @author(Tomas Krysl (tk@tkweb.eu)) + @created(18 Sep 2009) + @lastmod(15 Oct 2009) + + Copyright © 2009 Tomas Krysl (tk@@tkweb.eu)

+ + License:
+ This code is distributed as a freeware. You are free to use it as part + of your application for any purpose including freeware, commercial and + shareware applications. The origin of this source code must not be + misrepresented; you must not claim your authorship. You may modify this code + solely for your own purpose. Please feel free to contact the author if you + think your changes might be useful for other users. You may distribute only + the original package. The author accepts no liability for any damage + that may result from using this code. } + +unit KPrintSetup; + +{$include kcontrols.inc} + +interface + +uses +{$IFDEF FPC} + LCLType, LCLIntf, LResources, PrintersDlgs, +{$ELSE} + Windows, Messages, Dialogs, +{$ENDIF} + SysUtils, Variants, Classes, Graphics, Controls, Forms, + StdCtrls, ExtCtrls, KControls, KPrintPreview; + +resourcestring + sPrinterSetup = 'Printer setup'; + sAllPages = 'All pages (%d)'; + sErrPrintSetup = 'Print setup error'; + sErrNoPrinterInstalled = 'No printer is installed on this computer.'; + +type + + { TKPrintSetupForm } + + TKPrintSetupForm = class(TForm) + BUConfigure: TButton; + CoBPrinterName: TComboBox; + EDTitle: TEdit; + GBFileToPrint: TGroupBox; + GBPrinter: TGroupBox; + GBPrintOptions: TGroupBox; + LBPrinterName: TLabel; + BUPrint: TButton; + BUCancel: TButton; + CBFitToPage: TCheckBox; + CBPageNumbers: TCheckBox; + CBUseColor: TCheckBox; + GBMargins: TGroupBox; + CoBMarginUnits: TComboBox; + LBMarginUnits: TLabel; + CBMirrorMargins: TCheckBox; + GBPageSelection: TGroupBox; + RBAll: TRadioButton; + RBRange: TRadioButton; + RBSelectedOnly: TRadioButton; + LBRangeTo: TLabel; + LBCopies: TLabel; + EDLeft: TEdit; + LBLeft: TLabel; + LBRight: TLabel; + EDRight: TEdit; + EDTop: TEdit; + LBTop: TLabel; + EDBottom: TEdit; + LBBottom: TLabel; + EDRangeFrom: TEdit; + EDRangeTo: TEdit; + EDCopies: TEdit; + Label1: TLabel; + EDPrintScale: TEdit; + LBUnitsLeft: TLabel; + LBUnitsTop: TLabel; + LBUnitsRight: TLabel; + LBUnitsBottom: TLabel; + BUPreview: TButton; + CBPaintSelection: TCheckBox; + BUOk: TButton; + CBPrintTitle: TCheckBox; + CBCollate: TCheckBox; + PSDMain: TPrinterSetupDialog; + procedure BUConfigureClick(Sender: TObject); + procedure CoBMarginUnitsChange(Sender: TObject); + procedure RBAllClick(Sender: TObject); + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + procedure BUPreviewClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure EDTopExit(Sender: TObject); + procedure CBPageNumbersClick(Sender: TObject); + procedure BUPrintClick(Sender: TObject); + procedure FormShow(Sender: TObject); + private + { Private declarations } + FPrevSetup: TKPrintPageSetup; + FPageSetup: TKPrintPageSetup; + FPreviewForm: TKPrintPreviewForm; + FPreviewCreated: Boolean; + FSelAvail: Boolean; + FUpdateLock: Boolean; + procedure SetPageSetup(const Value: TKPrintPageSetup); + procedure SetPreviewForm(const Value: TKPrintPreviewForm); + protected + procedure PageSetupToForm; virtual; + procedure FormToPageSetup; virtual; + procedure ValidateForm; + public + { Public declarations } + property PageSetup: TKPrintPageSetup read FPageSetup write SetPageSetup; + property PreviewForm: TKPrintPreviewForm read FPreviewForm write SetPreviewForm; + property SelAvail: Boolean read FSelAvail write FSelAvail; + end; + +implementation + +uses + Printers, KFunctions; + +procedure TKPrintSetupForm.FormCreate(Sender: TObject); +begin + FPageSetup := nil; + FPrevSetup := TKPrintPageSetup.Create(nil); + FPreviewForm := nil; + FPreviewCreated := False; +{$IFDEF FPC} + PSDMain.Title := sPrinterSetup; +{$ENDIF} +end; + +procedure TKPrintSetupForm.FormDestroy(Sender: TObject); +begin + if FPreviewCreated then + begin + FPreviewForm.Free; + FPreviewCreated := False; + end; + FPrevSetup.Free; +end; + +procedure TKPrintSetupForm.FormShow(Sender: TObject); +begin + PageSetupToForm; +end; + +procedure TKPrintSetupForm.PageSetupToForm; + function FmtMargin(Value: Double): string; + const + Fmt = '%.*f'; + var + Precision: Integer; + begin + case FPageSetup.Units of + puCM: Precision := 1; + puMM: Precision := 0; + puInch: Precision := 2; + else + Precision := 0; + end; + Result := Format(Fmt, [Precision, Value]); + end; + + function FmtUnit: string; + begin + case FPageSetup.Units of + puMM: Result := 'mm'; + puInch: Result := '"'; + puHundredthInch: Result := '".100'; + else + Result := 'cm'; + end; + end; +var + S: string; +begin + if Assigned(FPageSetup) then + begin + FUpdateLock := True; + try + CBCollate.Checked := poCollate in FPageSetup.Options; + CBFitToPage.Checked := poFitToPage in FPageSetup.Options; + CBPageNumbers.Checked := poPageNumbers in FPageSetup.Options; + CBUseColor.Checked := poUseColor in FPageSetup.Options; + CBPaintSelection.Checked := poPaintSelection in FPageSetup.Options; + CBPrintTitle.Checked := poTitle in FPageSetup.Options; + CBMirrorMargins.Checked := poMirrorMargins in FPageSetup.Options; + CoBPrinterName.Items.Assign(Printer.Printers); + CoBPrinterName.ItemIndex := CoBPrinterName.Items.IndexOf(FPageSetup.PrinterName); + if CoBPrinterName.ItemIndex < 0 then CoBPrinterName.ItemIndex := Printer.PrinterIndex; + RBSelectedOnly.Enabled := FPageSetup.SelAvail; + if RBSelectedOnly.Enabled and FSelAvail then + RBSelectedOnly.Checked := True + else if FPageSetup.Range = prRange then + RBRange.Checked := True + else + RBAll.Checked := True; + RBAll.Caption := Format(sAllPages, [FPageSetup.PageCount]); + EDRangeFrom.Enabled := RBRange.Checked; + EDRangeFrom.Text := IntToStr(FPageSetup.StartPage); + EDRangeTo.Enabled := RBRange.Checked; + EDRangeTo.Text := IntToStr(FPageSetup.EndPage); + EDCopies.Text := IntToStr(FPageSetup.Copies); + EDPrintScale.Enabled := not CBFitTopage.Checked; + EDPrintScale.Text := IntToStr(FPageSetup.Scale); + EDTitle.Text := FPageSetup.Title; + CoBMarginUnits.ItemIndex := Integer(FPageSetup.Units); + S := FmtUnit; + EDBottom.Text := FmtMargin(FPageSetup.MarginBottom); LBUnitsBottom.Caption := S; + EDLeft.Text := FmtMargin(FPageSetup.MarginLeft); LBUnitsLeft.Caption := S; + EDRight.Text := FmtMargin(FPageSetup.MarginRight); LBUnitsRight.Caption := S; + EDTop.Text := FmtMargin(FPageSetup.MarginTop); LBUnitsTop.Caption := S; + finally + FUpdateLock := False; + end; + end; +end; + +procedure TKPrintSetupForm.FormToPageSetup; +var + Options: TKPrintOptions; +begin + if Assigned(FPageSetup) and not FUpdateLock then + begin + FPageSetup.LockUpdate; + try + Options := []; + if CBCollate.Checked then Include(Options, poCollate); + if CBFitToPage.Checked then Include(Options, poFitToPage); + if CBPageNumbers.Checked then Include(Options, poPageNumbers); + if CBUseColor.Checked then Include(Options, poUseColor); + if CBPaintSelection.Checked then Include(Options, poPaintSelection); + if CBPrintTitle.Checked then Include(Options, poTitle); + if CBMirrorMargins.Checked then Include(Options, poMirrorMargins); + FPageSetup.PrinterName := CoBPrinterName.Text; + FPageSetup.Options := Options; + if RBSelectedOnly.Checked then FPageSetup.Range := prSelectedOnly + else if RBRange.Checked then FPageSetup.Range := prRange + else FPageSetup.Range := prAll; + FPageSetup.StartPage := StrToIntDef(EDRangeFrom.Text, FPageSetup.StartPage); + FPageSetup.EndPage := StrToIntDef(EDRangeTo.Text, FPageSetup.EndPage); + FPageSetup.Copies := StrToIntDef(EDCopies.Text, FPageSetup.Copies); + FPageSetup.Scale := StrToIntDef(EDPrintScale.Text, FPageSetup.Scale); + FPageSetup.Title := EDTitle.Text; + FPageSetup.Units := TKPrintUnits(CoBMarginUnits.ItemIndex); + FPageSetup.MarginBottom := StrToFloatDef(AdjustDecimalSeparator(EDBottom.Text), FPageSetup.MarginBottom); + FPageSetup.MarginLeft := StrToFloatDef(AdjustDecimalSeparator(EDLeft.Text), FPageSetup.MarginLeft); + FPageSetup.MarginRight := StrToFloatDef(AdjustDecimalSeparator(EDRight.Text), FPageSetup.MarginRight); + FPageSetup.MarginTop := StrToFloatDef(AdjustDecimalSeparator(EDTop.Text), FPageSetup.MarginTop); + finally + FPageSetup.UnlockUpdate; + end; + end; +end; + +procedure TKPrintSetupForm.BUPrintClick(Sender: TObject); +begin + FormToPageSetup; + FPageSetup.PrintOut; +end; + +procedure TKPrintSetupForm.BUConfigureClick(Sender: TObject); +begin + FormToPageSetup; + try + if PSDMain.Execute then + begin + FPageSetup.LockUpdate; + try + FPageSetup.PrinterName := ''; + finally + FPageSetup.UnlockUpdate; + end; + PageSetupToForm; + end; + except + MessageBox(Handle, PChar(sErrNoPrinterInstalled), PChar(sErrPrintSetup), MB_OK); + end; +end; + +procedure TKPrintSetupForm.EDTopExit(Sender: TObject); +begin + ValidateForm; +end; + +procedure TKPrintSetupForm.CoBMarginUnitsChange(Sender: TObject); +begin + if Assigned(FPageSetup) then + begin + FPageSetup.Units := TKPrintUnits(CoBMarginUnits.ItemIndex); + PageSetupToForm; + end; +end; + +procedure TKPrintSetupForm.CBPageNumbersClick(Sender: TObject); +begin + FormToPageSetup; +end; + +procedure TKPrintSetupForm.RBAllClick(Sender: TObject); +begin + FSelAvail := RBSelectedOnly.Checked; + ValidateForm; +end; + +procedure TKPrintSetupForm.SetPageSetup(const Value: TKPrintPageSetup); +begin + if Value <> FPageSetup then + begin + FPrevSetup.Assign(Value); + FPageSetup := Value; + PageSetupToForm; + end; +end; + +procedure TKPrintSetupForm.SetPreviewForm(const Value: TKPrintPreviewForm); +begin + if Value <> FPreviewForm then + begin + if FPreviewCreated then + begin + FPreviewForm.Free; + FPreviewCreated := False; + end; + FPreviewForm := Value; + end; +end; + +procedure TKPrintSetupForm.ValidateForm; +begin + FormToPageSetup; + PageSetupToForm; +end; + +procedure TKPrintSetupForm.FormCloseQuery(Sender: TObject; + var CanClose: Boolean); +begin + if FPreviewCreated then + FPreviewForm.Hide; + if ModalResult = mrOk then + FormToPageSetup + else if Assigned(FPageSetup) then + FPageSetup.Assign(FPrevSetup); +end; + +procedure TKPrintSetupForm.BUPreviewClick(Sender: TObject); +begin + ValidateForm; + if FPreviewForm = nil then + begin + FPreviewForm := TKPrintPreviewForm.Create(nil); + FPreviewCreated := True; + end; + FPreviewForm.Preview.Control := FPageSetup.Control; + FPreviewForm.Show; +end; + +{$IFDEF FPC} +initialization + {$i kprintsetup.lrs} +{$ELSE} + {$R *.dfm} +{$ENDIF} +end. diff --git a/components/kcontrols/source/kwidewinprocs.pas b/components/kcontrols/source/kwidewinprocs.pas new file mode 100755 index 000000000..67269523e --- /dev/null +++ b/components/kcontrols/source/kwidewinprocs.pas @@ -0,0 +1,96 @@ +{ @abstract(This unit contains Unicode equivalents of ANSI Win32 API functions + not supported in Win9X without Unicode Layer for Win9X) + @author(Tomas Krysl (tk@tkweb.eu)) + @created(10 Jun 2008) + @lastmod(14 Oct 2009) + + Copyright © 2008 Tomas Krysl (tk@@tkweb.eu)

+ + License:
+ This code is distributed as a freeware. You are free to use it as part + of your application for any purpose including freeware, commercial and + shareware applications. The origin of this source code must not be + misrepresented; you must not claim your authorship. You may modify this code + solely for your own purpose. Please feel free to contact the author if you + think your changes might be useful for other users. You may distribute only + the original package. The author accepts no liability for any damage + that may result from using this code. } + +unit KWideWinProcs; + +{$include kcontrols.inc} + +interface + +{$IFDEF USE_WIDEWINPROCS} + +type + { Procedural type for @link(TKWideWinProcs.CompareString). } + TCompareStringW = function(Locale, dwCmpFlags: Cardinal; lpString1: PWideChar; cchCount1: + Integer; lpString2: PWideChar; cchCount2: Integer): Integer; stdcall; + + { Procedural type for @link(TKWideWinProcs.LStrLenW). } + TLStrLenW = function(lpString: PWideChar): Integer; + + { Unicode equivalents of ANSI Win32 API functions not available in Win9X + without Unicode Layer for Win9X. Only those used in KControls. } + TKWideWinProcs = class(TObject) + private + FCompareStringW: TCompareStringW; + FLStrLenW: TLStrLenW; + public + { Creates the instance. } + constructor Create; + { See MSDN for help. } + function CompareString(Locale, dwCmpFlags: Cardinal; lpString1: PWideChar; + cchCount1: Integer; lpString2: PWideChar; cchCount2: Integer): Integer; + { See MSDN for help. } + function LStrLenW(lpString: PWideChar): Integer; + end; + +var + WideWinProcs: TKWideWinProcs; + +{$ENDIF} + +implementation + +{$IFDEF USE_WIDEWINPROCS} + +uses + Windows, KFunctions; + +{ TWideWinProcs } + +constructor TKWideWinProcs.Create; +begin + FCompareStringW := GetProcAddress(GetModuleHandle('kernel32.dll'), 'CompareStringW'); + FLStrLenW := GetProcAddress(GetModuleHandle('kernel32.dll'), 'lstrlenW'); +end; + +function TKWideWinProcs.CompareString(Locale, dwCmpFlags: Cardinal; + lpString1: PWideChar; cchCount1: Integer; lpString2: PWideChar; + cchCount2: Integer): Integer; +begin + if Assigned(FCompareStringW) then + Result := FCompareStringW(Locale, dwCmpFlags, lpString1, cchCount1, + lpString2, cchCount2) + else + Result := CompareStringA(Locale, dwCmpFlags, PAnsiChar(WideCharToAnsiString(lpString1)), + cchCount1, PAnsiChar(WideCharToAnsiString(lpString2)), cchCount2); +end; + +function TKWideWinProcs.LStrLenW(lpString: PWideChar): Integer; +begin + if Assigned(FLStrLenW) then + Result := FLStrLenW(lpString) + else + Result := LStrLenA(PAnsiChar(WideCharToAnsiString(lpString))); +end; + +initialization + WideWinProcs := TKWideWinProcs.Create; +finalization + WideWinProcs.Free; +{$ENDIF} +end. diff --git a/components/kcontrols/source/xpman.res b/components/kcontrols/source/xpman.res new file mode 100755 index 0000000000000000000000000000000000000000..8c46dfcf44832955a00b4c29bd6d579e44a8a59b GIT binary patch literal 648 zcmaKq-A}?W6ve0U1rpwUZ2D-j!4!xRCLySaF}|Tbm#%}x^>%3sxW69nzHr8mB~7+- z+jGzFcAn>X1lQqEEqwj<+@Ch}bKG-M)&^eZtl2c3eW;Y|gt1aXM8jY}i2$x+3G0Zy zEFb)9N~~iLvs8nKXf7E)EB{pR*@GWaun0!gyA`v3p{ literal 0 HcmV?d00001