From 08c70aa14c41706943a3b764549ebb8b426cb285 Mon Sep 17 00:00:00 2001 From: MeowOS Date: Mon, 31 Aug 2026 02:38:32 +0800 Subject: [PATCH] =?UTF-8?q?feat(sdk/view):=20=E8=A7=86=E5=9B=BE=E6=A1=86?= =?UTF-8?q?=E6=9E=B6=E6=89=B9=E6=AC=A1=E2=91=A0=20=E2=80=94=20z=E5=BA=8F?= =?UTF-8?q?=E7=BB=98=E5=88=B6=E7=89=A9=E6=B3=A8=E5=86=8C=E8=A1=A8(meow=5Fu?= =?UTF-8?q?i=5Fdraw.c:=20=E8=87=AA=E5=8A=A8=E6=B3=A8=E5=86=8C+auto=5Fz(?= =?UTF-8?q?=E6=B7=B1=E5=BA=A6*=E6=AD=A5=E9=95=BF+=E5=B1=82=E5=86=85seq)+se?= =?UTF-8?q?t=5Fz(999)=E7=BD=AE=E9=A1=B6+MEOW=5FZ=5FAUTO=5FMAX=3D127)=20+?= =?UTF-8?q?=20meow=5Fview=E9=AA=A8=E6=9E=B6(meow=5Fui=5Fview.c/.h:=20?= =?UTF-8?q?=E5=B5=8C=E5=A5=97=E5=AE=B9=E5=99=A8+=E5=85=AD=E7=94=9F?= =?UTF-8?q?=E5=91=BD=E5=91=A8=E6=9C=9F+page=5Fpush/pop/replace=E5=8C=85?= =?UTF-8?q?=E8=A3=85activity=E6=A0=88+sub=5Fpush/pop=E9=A2=84=E7=95=99?= =?UTF-8?q?=E6=A1=A9)=20+=20=E6=94=B6=E6=95=9Blive=5Fbtn=E8=B5=B0invalidat?= =?UTF-8?q?e=20+=20hello=E8=BF=81=E7=A7=BB(d=5Fpaint=5Fregion/d=5Fredraw?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E2=86=92meow=5Fui=5Finvalidate,=20chrome=20s?= =?UTF-8?q?et=5Fz(999),=20demo=E6=96=87=E6=9C=AC=E6=B3=A8=E5=86=8CCUSTOM?= =?UTF-8?q?=20z=3D128)=20(agent-176,=20=E5=AE=9A=E6=A1=88=E8=A7=81SDK=5FVI?= =?UTF-8?q?EW=5FFRAMEWORK=5FDESIGN.md=20=C2=A7E=E2=91=A0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit meow_ui.a d814d0ed→7e20f10e; hello 0a1c96a5→2ce09466 宿主验证: test_p1p2p3_repro P1c/P2/P3 ALL PASS; test_meow_ui_widgets ALL PASS 无回归; mipsel -Wall -Wextra 0 warning --- patch_v2/hello_app/hello | Bin 262204 -> 270268 bytes patch_v2/hello_app/hello.c | 152 ++++++------ patch_v2/sdk/build_sdk.sh | 2 +- patch_v2/sdk/meow_ui.h | 52 ++++ patch_v2/sdk/meow_ui_draw.c | 357 ++++++++++++++++++++++++++++ patch_v2/sdk/meow_ui_internal.h | 25 ++ patch_v2/sdk/meow_ui_view.c | 197 +++++++++++++++ patch_v2/sdk/meow_ui_view.h | 98 ++++++++ patch_v2/sdk/meow_ui_widget.c | 48 +++- patch_v2/sdk/test_ime_fix.c | 1 + patch_v2/sdk/test_meow_ui_widgets.c | 1 + patch_v2/sdk/test_p1p2p3_repro.c | 34 +-- patch_v2/sdk/test_sdk_fixes.c | 1 + 13 files changed, 872 insertions(+), 96 deletions(-) create mode 100644 patch_v2/sdk/meow_ui_draw.c create mode 100644 patch_v2/sdk/meow_ui_view.c create mode 100644 patch_v2/sdk/meow_ui_view.h diff --git a/patch_v2/hello_app/hello b/patch_v2/hello_app/hello index c63acbcd49f0d898bf5b620445c17222a5a92851..d07d3df337a047a9ce3e29a0055c7492f0c9aa5c 100755 GIT binary patch delta 78915 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π|+r)aXyb)P#@H<)a^!_bo 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 delta 72359 zcmc$He_Yg6_V>M?8E}A+1{e_$ac20;h)6an8QClih(<<6MrMiw8u%q-m0Gr?Vx6(2 zmThN|{IGu5Vrwumwk4&qvZA7*qSjg}E84YUciGl$t)yrY@VT_G_Yq%pL-`DgcWArhC#2CkajI|<8 z+30gLq<*3z((5)DSlxzb<&z>XX7w``t)))`)*`)jLli!DJnx7$PDkz2@A&wxS?@

q`Qw7!=sp%K{UDgTS^y>2B^yZFo*#9r&1D7g*r;0;_#PV9odpz4^!oeATMNk+rB5 zpTqbZ!KZ$$w5+(s&u%fW%q9bC$H$6K(QO8neTRX$cN>@}f!1bVL!f8hiX!+l;ZuP; z!_5XZf{*wU12g{A!1_^7=^g_s!>1Rtfp#p}U0C}RQ+gbd7fkAd|8vwvZT zV@4!ce_>#0zj$QfrEAmuW5*F5Gq6KnfQioy%=}Lj_{_knqm0b`B`U(l`?Y~Je}zgu zHLyygxsk_;@F>!<#|cvS%7uFVL7`WJeJmwxiArBMUf; zY!sh5hta?aGaiYqjTQVIx1!K($OtR}_5z2>qFKq^podQVth?vb`042s_ui@I8Tz%6 zb^l6@6HTWREux&CnNg?%nUCU=8_|GUYy5ZwjTjg}zQTh>CgPKePYOQPHZTt?!)NqS zBddPg$VMJR8n6!72Q(itvSMHbZ~(MyVCiEJQ7an2vZ7Coex>m)5NiK!Wa~g2KaHWmkN=aocI3~+Cxo;*m$d6)23!+#* zK7;u5AYKHd&rwRlXH=sfLikYrBg=k#lKUBK$~`bu$1mV4h3t!$vs|DJSOP38;H(Z< z4QvJ;SbFnBXM0t^8=EU>qS5a3@ zxDI$6SPL8n27u-VP%$tK*bU4C_5pK%L%?;vw%RoLur5kUHqat7z(42}M4`Dh1 zo8I887#IRp0L$Kl=z)iT9l)GFVp;-=jzX7!hk@qV=-B(v31Bub7uX0a2KrARP=P?- z2M`ry_z+_VtQ^4@0=xeNkpYkV8Pg3I{0nC%2uC5YG{#NsDYKhG2j@`JO`2(2P1PZ|A!DL0ipOS%yZ!2*BC2c*EgsD=$=52faY(}BVY=U zr9<>UE3g!p39JKpfkEIpp!+0-4j2G70|$X!!0t&*b6_76*l0TD{|EvTAcVNU(&j?D z?E)(TW@o^20=5I2fw`ifX9Koz_xS2 z7_b*O3Oo#)01hoh#~jE9%mI2lU<_DXATWOrfj$I6z})5F4A=`i0<0|**f`LnYO=PXWHsC?vAaD@ac(uTe11Esyd6@6(Q4w$m zSV-{==m5}Ch7JIa0(*eojRG40o&X*LcKZZo$wa<#fn@_L{0I~xkWzs$0d{Y~*aAJ9 zp=`htzyaX8Yp{6$HUh_hIh6u4&Ig0QOkki2^#DhKWx$Rt0;>a#0h@tE{{_hayMPBN zUJc0t{j~^;AkYpR2aW@+S+I!LqGF&}15p8sfTh4XU^VbCun9P^6^sJiwHRw)2zUfI z06YfF{=UH20!RpG1y_5!n%*GG^vw=r}Uf?lcDRA(1=myXogam+1zz{IB8$Ad10!Om_n06AB1BB`h^!RLu z_}8ci*mE~T32f^`1;ETM^b}YG>;skphlqY3bOSi}0D8C(_T;yiX26af%o3pGK@0`a zfo;H|{g|%63gCbrfnyJ0Oo7HnFi+1x!Gjn}AbS)_1*`xz0vmy?z(HUSa11y=>5pN) z1CIik8y&%BGaE>o&O+b_umU*o3}y+i_gQoVSUrIGe;9#r1dag@z6hmSgz5AWv>P}E z^a2}Rh9rQ;fek?0ASwcu0Yktb@DT7Qa0oc~JAs`5Rvv~#7NZ<62iX3az}5jrurI9# z77ty*SVxd%z4_tQgV?2=mz#ai@h^2rymsn3xPpkBd`m25ZDJC z1`Ywe&w(Le@yn3R`A{-o3NQrB1|9)=ffK;e^D+O$L2T$L1F#WT`wBP&HXO#rA2Z{0T!K&Ov(l%( zNEaHOlj2*Fqv+73R+`_EA(&p5R<|TCrPG(=Tq$NNzK7o-w4x0}NAaOknbWJB0KNGQ z>CTpPVdzci$(GcpiMKH6r8ndx>3ECD96SQ!W>M-ZlK#{_Q=0qBs6y;J*vKg6I_RuK zQDccT^pMq$wU`Zk0t=xM`x8s<;k$)946Ue|`d0^f_868O zs<|+}nMb7CKx#$$$Y)@a(yQYSMVH;fe<`#XB;)R=JEB{s5xcO6toC16aWHRLZTxt< zL1?&#-z~_7J<`ux6YL{MANvw^7Rl6A8X^+GIOrAs25-`)14%JflVS=3*vDQ%_>bPJOJAGX*B33Gk!Cbj|6fYG|M;A{ySXJIGtghlhPmV zNEbZ__D^C}&}yWdG{Q{`lM$j|mGPO%NZ<2NRCFT}nguCucXD()f+K>oes_9wAA%hQ zX~%9?>M;b3Q80*F=cu*`&`P7FXLh@yGoxS?Owz~5S&HEC7}(l~oYkO(;-oCeWobij z%#8CnN-m98HTT2aQI>url*YqApf{`{ex1tO?kMp%5^57*kwB+EYMMo391>w1sFp&t zmN+INl8uz(Nz$j1!%~W1^$gfP%2X2XmE0{UnT;U!B*Uek6#gFnCOg52dil?v{+guyVAQ5G%dqAgB;Mh65agtQSN2Z4mmky7{O6w>60G1 zD@p2=jj7|5c)?VY#J@QfntFlsx||xFjbM?7%0?F<81zW7?WyNiBPf0kD;%|iKjOU+ zv^LNx6^c4pT0tA9e59v^@gtmcJC=IThm>lsw4)t7A=vB1@~ZOGZgh-;(wMJRb=s0) zjf0WMm)>c2#dr}cSwWq_!nBfjr~t*ha;h^#s|PIwv;e~NN3>?p+CfwF4sqhB1GIxH zCEu@-{f7`Nx@f8zQjEi(m4fC*Sl3~yY83P)&}~G=ALShft?RVB)Px0EcLa1rM3@Kq z&{LUgq~#XDiC`=-JYT6$Arb=88^4;lssf==WFdu$WT63c)5TMIPSpiLO94&kp*H0* zLGJ=R=VEEgoi57|f_=r>>@SSZmFo7Tq>h8wdnvp(Y6E|S=INNemrAeS>8hbK+0bP$ zm887*BMB6PcBo`ZnABtiXh%Tnqf907nK<;5gx!WajIB|MumebMy&SF*rJpv!9Y{NV zx#YXc6+=h6)$1`cY3-MK?=?mr2c>a?wEwPDzd0Udu_TsI9d)WzA$~;AOF*YE{Snd` zaD|>%qZNbJ3t9tZ!XF8{0<_GHaB7JF^Ab5ijYu0qS{OzLBuO>mTtd0 z-A`xZ-o~l9iYQ|V=m2OY3geGxR?td8%TXxmJk12H88l)KP3r3s^Mc-W8lBi!2YNr~ zU21;P4(aA6V&>F?Uio896Ol%Fn?XAWT9LFUloZp2*aTuD(&gPV^9B$*x&vyhisF>n zL6dhB>0|y=Cpz&+=lIru^vpe}(P=OeM*`9Z_qbw;5VT<9R-#N2_v6OsT2LzXN()2D zG0g}b-izIu;=EUcjIrII)ZU9-jN(;9AEvxrQVa4PL$I$47nu_8oGDrQjZ4i*kjuU) z+esa>fi?hIF~X5k#D=H`X_ot?lcDsO3Iv-b#bvpcJ2*-@AXXJPhOLWbU33?O4V9BCu zE{(evX+20ApfvoEd`t1ay53XkA$l$T7o4Ii?g-JF@W1X}gI{kr?09z|VE_e6kcs|? znO@Lr4`G8%vr;GnH@lS`7gcl^{~N?!IkE#pAI1Mhr|3%k%79biqwtzZQHrIP_9mvM z&A>E!EL=s{Wy%5F_L%hLURP`df^|=!RJ64EzH}+H+qftQQUH76I@CjdB$*IsW1uxE z6x9YD1g-XY*u=29906q%lwR^IQ)9*v4ZWc2)6l)f7`j67V#Cm`6dAkM=+6aZ7?cXC zxPHnomw=x8qQ*Lsh>1$jN+W30;Rev^K(isNPfN<%3VQ2ldFfuJ=hVD$$}rGH&EXfN z9bL(>!w4RI36Bi~>F)Mq=QyH8uP7@m*}3p4Ov+}Ri6)R{lK8>d(~05%rTta%PWXLu zV=ED>{2f^U^0OuHea4t(kW4ro7?3W#Z?0tfrO|#6l*6F(qBu1`ei#|i!=N|5rsY&B zr%NC2>o^gRp1W^uj1B5@9I;+%Dy9grj^7(thm^2yc62RbxkFg@lF4gx1QG2Unp(Sv z(-3GmZ(!|GmF0u3?R4qn#)(KN^06{il+>OGdK2gYvZpbH zh#CJtvFi}4q%_3(r8~N3$222GXDNq?2PX-n2NcUu%?s1&w1GYVdOhd|rO#0A7-E_4 zQ;gpS5&XvZJqzxej)GE+ypeiCb!H>2@B_^dXmvt{tPu1z&<{!1-JKLoH(bRZO1J+e zJ*J5&8zIp=^qbjLbj4NoC(Rv*aEGYs0i#2s(`y{Sj>pv|i8-DHPS~ zFhX9{f6-d<(cTcRdNu-VPx*2%z|nuDDz>;{I{vDQQi^ILZD?+UTsp5gvUWY40?rh z`Ta>7t+<-YK88`FT==7snV^k;)<6WINKqnc#S8knzfZM7v{KL-L8IwPf7C)XXkDO{ zDP!1#7@bW0Hr?Nip!*+F%1n**fmR7x9l}iTh8sHq`Vr9e(W1P^KpO{5Q7BDmhzYt^ ztT;ZEmzbeD#wO6Lm>!V#AzpotbV<*w@6%mldla7KP&xc5odC@njfW*FNugDP)&QC< zg4Rf7LCcAtwSqPT8u3SeBmlav90jdVab@}u%bbQ6A-cV{kAN}(3Pyr>3$I?|pr@Gd zyhq<``crUGISvXo8Ok4Vn+=*V=2V)OE;J)(#7!w^X`qcz$x`*Og1Dp0(FxG26|)zg z8R@dqg=u9R9uKKy&I+625E2f>Nv}TWT1JYP2DfsBF-ok{<@J~mT~GR_JP(2nl4k~e+aZ@(2gJ+dB#B6cN}SDBAy)K za0?U3jdvJ(gkKukj8c@e;K1}~s~vruFXbIbb><*wU4S=P$O$ook8Ww8OOQ5%wED28 zPzOq3HlCzmZTwAgA@R{h6`YN+p$dwpDxh(vyW&QqQ9k-3p$vf523j-uPWrJAb~G_# zNJv`*6_fZc=PD;Ebd{XDSUUNL!(WKt&=NeFqH1s?7b!K;oJyqU53Ypn7_cHi0zaR5w8=8_NceAfAf{Qjo>W>`|%~u|_ppSZYeK z3@G+eBMYh>RF4|z^gJ609p|4~H}O*l`T*!9R9VC-O_fz3&AJQ{G%9JNLMhX!P!I|3 zJR{aFT6MY+8_kn$e>6SjFoGS+p}TYt?L3B9cHxl?+xVY~Lls zHC<}Zz9J3 z^ixL;g4Ak_Qf+^P{v8HAdq$MfDP&V-IK2}nj-XNb6QI?ChJKTP!n+T%3-yAo=&DxU z2HH{3>QuI~EW~dPh{ZFb)Wgw;BS(@{3DTO8)*wB1Pm-cNb)c{myxEiTA4^&lM63w0 z0EqNQ6DI`PAZW_SAWm)2JB5^4S{vAdMapXkX{EEIZBNYfBNRZc3Y4Hfs*TNqB?OJQ zp+Bn43fcr{ULr))MtR&w^Q7W6vYM6>Io*{WA-x;vAvN6=dG_R@%IlD!Xf`^iW;lh_ zAktcAgVp5JZUp;~t(CIjkBatzR-7i?{X}x~FoMA}>B%QtF-FYB()1|Sttb;VMSc;K z2~ZlSAS`Dj4^&Sf((C6&>F!gCzGJ1d3ZxAptxhc)P9s@0A}!Yzr5aSkNj+LY3xTG{ zPgSq06lUq=MjsLY#6)w>Gh{lqs>`llBG|dO7_!J5c9cFtc%)+*yt1Ig_I3x zT93kJqzv>UpyyDTb*gzGG1r4`S_)CBGbJo$N^3=0-FeUuN~?$u392^7DgEj};-Orr zrO%Z)j9~w=Q`@BW$3Pziy-BURM7jS-Spet2qs^LPbsAGKL{Rm&)Lg6Q;qrS~*C4O$=Q$3RykhB)3sDa;^FG5pji zSjKdbrlcCJGeY44}sWo z$&}rpjP(4*TrBN>#u0M@L3atXUV7-6*;4PFQU0@G8F8Peb4tB;gVqFE#5_}&C;~kM zdLQ!8A2CKRcFL}tYL94jp!I>)K$-AIv?kDU)@rs)qqT$P4}qwRJ&4qJ4~XJb;klei ziy@8I0O-Y_2N6bZ!=5UY89~}G(lmy{JO6RePk`R4mC=ol4RLxp)U+-N$AesIc{G_$ z0b_DOYgiw}PDqz0%#_^yrr6B)znQGSr_~`9^yfLUueOU8)_K6nLO5yT9@|rP(a3JY zNAOgxxk$WlhP1c8U{?K8%*>fl91^%#i0mVri(cTp(zpFH{gjF`EAgcR>bdR3zbBX0 zC{l&F&pO3W3OApHcr@a58`K6H5YOgO;uwn-D?f+gvS~_s*TzL6zWU+`@x>@_QD~u! zj-J2pB#eB13o+}oF`*S@SE*$s>A6LIsv}FQqYwG1jz^}eZJj_{L&!gXb(4v)o5~# z!f&*~+AxMN<55+O?neJf--+e74=}UQXH$lEfIGz$);o{X;qc|$oQC0j!N|=NU-BrAhM&^=Hi|(?r*MBnIE3)zK~?^G`cOprk%;iH7QPVU zI;e&JE1t$!45lAe>!7aR4l(JI2=+sIVPL-SL!459xe$@gL^!A&owCicI?aH>8{eC}nnnRUI=z876H?ETD4gLhW1eu+ZG z|McQqKNUzr0T*++h$pAnC7KymrqmdQU9XTBuz!QE451H{Z}_ZJ^VMT2Mdqa`o5B`D zzG4fNBc_dPk?Whu#W=53#|`xIu)rykE^rECpp=HbiE^Q$hvpFjq?^@M7X@n}33blf zgugmC>_pTlOdFv%PPdJO^1(~#vA=y$7m5`9@LcXSM(E-vDBUQYDIXNX zj|YHLjRn3|8#{-26$YrX`YHzmaFJMFHBZs(Pvcx-wx-$CX^S#p6BSJz-dNa@%aSl- zte7b?Jh(Cw_wZzdXL?R-{L^k?B+mAnFut)9;V3aK)4x;5#nhnb<;-P*DqVwTcw@o- z@r`?TpV;_UtCCkWky4B1|E5MBdDi2B4)M_rX8q?^lsKB?A2DtyaXQ`0Z9Ua)bFVoMvUDnix1E5ueTPdRL{ zVuMnAcG1Lg#3(ic%vH9i3`ifn;wl*P6>3qnzc*<75S?Q{wthBcWsT)x5K~^Ek$j2Q z)(z6?R~`Nl-%f~`#%q&s%-5-jJYP8O+k~(p4n^#vz7>k4(hW9Q{u91iwX#*hgzp-y z>~evX7qrF&3WRZ=GpG(3J7vhaHZDPLXfdt&5q(aM6gFK$Yzr2CCkZ2uJxOTOQwx&n&uNd+ofDj^ICse&)qpUt|k0gDo!zg)We zcWYKJ!L0h_bT=4E^cc%emFxF34v2obT*rK8lxyDM|37jigQltIRmvRLt?^FQfqbX` zv<``$qo?W7yDRi*5hGSW@2xr8MT zOM72iOz_TY%Lo!*S7Iw)&vQI+7B|xXIGfeU*jVN0c^hL3+AcRfg9*~U*H_2VT1Aun z?E})u*U$6A=0r}ve@;%>u4>J8Rl{}>A9Wkt%3_}Z8|K7HO!mu$(WX^4gnBG^f_x_D zkHiy#Nt&9TiJn$XJX!j@Pt)X+f>nbOIa`6Zdo-V%Jtw~=n)Jc%9sYptXWHC|;my85 zZEke4Am&M2?sCP%G+};BwZ%OLp-z!~#0iFlv^E4;J8h9>FVQoo@ujn6)AFwVf|-#v zyCq)@KxnFzTOkyz_{OZxd+Gd7l$Z)z1`naQ$KJ!Fzf%TE=3J=%{H{oHWZES@U((SsXd zcN7N;=vIC1BV>D|{5R+ME6b+_yS994u`J{c6Da zrRTX8`b?wn_miiN0!g?OBhd!Q(t;2yFOd9i*%!7WzUMSaw?_2)*yPjmtnAqX)Q7q% z>GiifV6To{Wume?jIsdX_SW+PU5WO6wag_ zZ#n$m#n}6gsP0s{@}*K$&B*bM{|>iG&ri*r?waXowAdfT7DV^8e`w@$l*LESK!uGy zdyu>XyUoGmp?i6nNcrc}0`uOdvXd^tY_9`j$9f#jk-mF=sWB3l& z%bL>M&#X{Zb;Vb$lNkd?e6&|NTc~)pCT1G&OjYqbzlN7joCJZ>sm%)4_bMi#R8f%oP3eB138R~3;=-RN)gc<0 zv_^{7n~712kGGhajn1yXI5w#ji(uvx z@eyfXtxPk{*0?BNmMLHO3IkxpKG5Q0sNI4U%-CYo23gNvR8DE!WA#Zbe^}{P_rL+= zRE4YwZEC!%P)zZC?&>P95-*A(D--QGg0FvOGure_^H`WknRFbRBC~Hvr-^m;bd^{4 zSbhKMF|)P%O{{c(itpHdlWzb*Xk|vEXEc|v^~~+U6&0GFfv$!2LnX^RC*!Bi!z^&x z=q%+3HbT#yz#N1}9?jB``Q8>U+muOL%4*;92LdLXSK1BCZrTaC7$KJ?k-{myQS^63 zi;1m-+%A$X`C!(i7GLN7G%%F{rmSdu0`tJa@)3UI0NJh&v?HsDGqhdpdv2Z)=2dTh zhVWy=(){m4yC7OZ0VNwPig7N_X|?>vNWRA*gcU;Z&5gwKK?MB8d~~+ z($JON@8)Xh`1k2VYHl0$p7B1Su! z6)o6Fwa~_k^wS7E{Ce_=WFxbQjo54RY9;T@C?T{!7~(lqPYld6nlt4Oeoa1Nwg~Cc-hoJ9UVdjeAkDX zeQQENoSfOX(?#mrF_$e19>wqot{HM-mB5M4Eun%;ahFC3bfBJ`aU_Z-%;j z4~KeuyFjcjRJcs^bo*B9Z{4s7-Lx+aT5(uesVINv0SjhsKesA_Lj$u9?5hJq zZaHbinON_J6P_6!jU0{bC1JLSU414{m}3uq$X62T_qjtPm;qp$!djB2&sU|GA@X8O z%noq~IEmVeWARR9T6UhLnuRnLS^##fV0VUMfJn;3^54StArbQ6*dY+x(&`V><8)E? z`6{LI(ODORC#5ao=`i>?qVY2fe3iQ)W~*n&*SepiLe+2jl00qo+~%lK?ea4WNEm1B8HD?cpNx^4w3=d8PW3CX=NiyZBfrpK!qo?Hd*=N(C5lXSUuyuTVWKFl(vZn#f0eNkNIRQFW7&Y!S#nN?)d*$ z2=EfI-y>#dYX&t6TaIjmiB6V;ju_lp8XZ9p6IMQR zxuSfR(OlMtfb3ox8WhoBCK}8aXpSd(Y~`wg(qvf2<^`_=BM;$>{tdK~06RhDv$Zy` ze#GhuZY!5Q9d-CgNb0;hld!&9R?DZWva0_MS+ywguzK9(w_jj^Yux2cu$oI@`_9#jh&yaVA}1>uklgZ;khfelAcera z3RB$UDR=f*;T>{z4foumE#fxlZwSVLRyw*zQ3Y>>BXkQ4p&bjCGe~MiD_~Litu3FU z2RY@HE#s&(8^SI|d3|*(Rs^oDj*0r}xay;VzC?j2>al1~# zGN5j7MVxHvYV-%3(28JEZP4PWC?}tghH^Pp#!V3`BfOpYw3v0$!bp=(T^Z3J#CR^m zNVeFCC4{Vxx{{GTkb5(UMi$~Kqyny>9uH!>78%b%I!THoR168xNdu+-A5Xro&r%gC z*YMv@J~D%qm;<$#1JrOGaE*Zs@eEIOc`trtAxYHzv)P(|Xo2D#VKc>S7fV+}_@9oV zRhf+S%DDZ6CS%x6R+o1{QhAWnd78p4jZnCq5c>>IBN`@V8Z@Q?8a4rSW|G3rVj`GH zQWm5$IgV6MbGgHa73n9^vm;ZCG%Adc=94o+tG@2cY{C%y-%Vq)X7Xbju-BWrQR!da% z->RjmYKz1Y=4^Qk?U46aif}HDU+5?X=~12#c$0^cxLfl4BhySrnz(acTXwnSW5vMw{bnt=tJXggP zi2FD<#|HA5dIDus4l_utUk*~k zoP97a%k;eAZ^|a|-!2<_2wUqJSYA6@varc?HZ#G-I(LC7W90syN$l z=0F#C497NcDV<>MN9=5+K|!%|9Z0WK(&@gflQ~TAFTSv^b3y*`v5C4=E?|X(*>wte!IwlhB!6W>yfy z?g=K%fY06oxS4_)h6G&#B>GuwBy|M-FUtGz06{%b0TV)&X|q6^VrrNwKf2KYuGiuh z0;g!B$e)YKsS&E&Zn{Nb+!&FE?u3VMoiZB@>2=YiA)Val?Wn`+R~tHp#BLnvs2S*3 zXDzxv)#w<~>C`MPq%;Ud^M%tJ)Nl1qAnzVN#bB06#%!Xx1d$l0j!h`cK=S@fs<2BL zFMWzohH+$|Ck<*ZY0USqxCn-nJ5`)N*-eFK>^(gzh@7_Bud375%X)VeLeGlW!@G*v zBfI3ZTApIAW>3#Eu@S7x_}Wk4c+PY>?01If7-dEFR_VFpNz=6RKY4o^pCz3*p6%%J z*>US@5yvL!=9M%vAKYL^#vGYsUVD5}!6z&Iq|DSIT8!U=P8qSVQykU^lEA(h`q1Tb zY8S}23O&9R2$LdL3BAg#B;8`FXPVu((V(&^T3J$hbq{I8{!u@}{Hf643!jVPSrT1| z1eUY*sq0MYgx%kZrH;h~95j=%=w(P;0KYp(&r_V( zC{kr)c8xxFk8*z1>SgqfgWgIpR)EE4?}3bFH^ye_X^v`!Z76Gn8Q$3f-H13=I~V1; z!q$?rAK(aWCoJqH?MUrWxF-H2n95Bp2@wTV^O%FebYFd2%f#fZE#s3-Eh*ZwDSZxe z_Na@>W|=yLFUX3)qERPktdq6#xii_16!r-0M}=xX{AVyAFdi+`%TtX8<7<)1 zoxvabqzC@#;s>QS{+SeiVuKjGm<5!Kfmzb$|6J@dlyLKj4TUX}c#d*ngSr8CPzhO}mZJ(JV&-BVpqo2POlyMtBImt%|L$2Yjd)Hx`Qo8x~!B`y6dU8u6k&ukLX z?c*Cnkrtw-qg{A87$qt`l(slkS-E+s{M;sCwtpCdr)OihM%1&BNgA%o-)+;3=m+1U zH(^Gxl-+xv1QVo87K$E@it>|Y;(&f2gzM~OG04Ea7^UpDogj4OxC zIELHOB<9C$Ss)HqUE~^vu~Scf9>QTy=K*3O0A@(|By_60$||k@+#zHZNjpBr>*gX< z4O#9XD2HAg<%*|cc z)l&T@Hb`quWF_k?9*tPy)>TWpPwZA?c_yxiOKc$xC9jGYWNFnGsmWFkA9{xfaGwdhAPA;!^NNdi3n1SDC|cR_W6( z(-Tw1=ZQm_ijmr#UnHgfJ6Sk>nY8rZi(~J6TD2y~eEq-otffxSJjNZEV(e*QP&=mT z{D&rO(6-D|^q#?icw4I?GT-ni`6S$Z;@v6Xq_RO=k8JMoK4wD$Q3n$Wg(@U zx%BB4b5Zc^94Ypz&BD#+N!z|k7QVbvy6vmmQVX9^CxuZ{S(B!+y)}~S>nul6*?jnb z7vq~QsyoJ6CzjO^mQ}7;n8GsY`mfif(>e0Nn!g7{W}~l3GJDCr%2x82wH7TX7Cy1H!RpAmreYTLvK?& z6*bbU-)6-Ym3fr93(Fok`E4TSg;K)g1&U%<*GOw7vy#1KwAm2wyNM2~?z})cyC)aB zijegDIcP1@$-Ma4Eb8*awj`LK{K~KD zCKr|EV0}#xW0YU~B{3(`aSt|!Heu}9U+&=P@sUzHSo6yV__9^hI5s>?pD=38MC)XZ zh|cT$CxU;foAOoE*n@(}Sx4(-ZH>H;^Tmm0pkL3qLlcF3C+BOSHMDaO1pNwL(VAvx zO|z~wa-zU}scM^;+)Vj?IJBxzYgfKq;EPdb6t(-jz*q8CImW=}qN8$_fiLET@h<{W(&Z8u#nOv3J1;D3@3 z!JKH9cN+Nu3-yvz1_o-h9*iq9nO z_C*nQkG~hie@+TS)yOr|`1;5qUrytDsECQ519;k`mVC#g^eZNY|3EKzOAKEb^EYkN zzg>PKhA*IcPR6KBFO20Y=j1LInyHRq14rOO-lA25}+Fuuif+=bk$J1{$9AaeVJ-YN62M&HNp` zBOjZ2IteRwI?tjWES=7`khJbb9Ao*)bbg+mH9DTZnXHVZoADc8Q0Ie{?b~(idHK_L zzA(O7qj9!H1TE_KR~cR=VJn40ILXY1u3C-Zas`uUH(5jpRa>F-8M zbwXTV6UKUmr>>^61^$$k)>+C=lh)Zz=LPwhdg~2am-IxjO)i?ig=GaOpHF8&5fglA zFkni?q?_sKsTo~~qdikpve0C1avM8MT6~8#u)w&wmLxz;~leVwx@!p&KK+>wZ8h4Kz zoQYv;Nalt9qOvt$_hA;-+Ns!t9vE>^Q*p{piuuA^&I;zzVRi=c7+|k%K=lSs!`AD9 zLdw$XUoc_0u(|6pT1z0ZD38#-xQ=$owKew!qj3Cd4{c)h?m}1$^fWW1d<}sd4SQ&h ze8EgUYY`0>_2C|^4>UfyactP?4C-fe8SWB@iV1f4)|t?kN90##@{3lfvtM0jp3sEj zY-ijV8o_B_ztXLGnAi-Yk>S$2MaxKfgc+temckdG8~YxVCl>}EM*qBFgfqc5wyPh# zi!gNo4!LgpR7LX&KbD_M;XmSwI^}m#xeK%O+f=@F);=7*!Mv~x+vf1GB)R2}$UA5A3lxWh z`ZP`JFY!qd>qE$>CR2(7l8BY0E-pPsM!=;${dQG z4&w+y#1TY8&E_6zv=NPxeg|suagTrBJk?Q}@#U4Y-&x`M^ z=?^v6JkWEnCeYJdBj?TK1^hvI=UhJXYO0X>+7RKBG-}}nG?WGz#9CAvK@Gc14n;N# zK*M8%%s88xMs>8-h&{R#;^oig@&&5~wQr4_?zWLFi9D~XMAiE7D6!OwbbV+jey~Q~ zV&esH3gwd-oV-H$c^j`0O3LJgcAo6A3^G%qja+eclD45f9L2&$Y*y4Yu+=HK#R}T+vTajAr(LL-EoZVZ_pK%!JLmVq|rL zK_^PYTT$7fu+bpH$FQ+g4)*0=XYko8$!5~m&Uztsnk|^^n>ut3TXRxdr8{eMy``p|%@wSWJ+_O6#*32|qbB$wHD)C796=OUT#(1UxW9(pLcs~ z8`RO0&vNl7nhMD-*cwcYWiGxA8<{9i^Va)=&0Bwqb<6C@Fp11=yNE5wjpnUen|}cb zI$O8i_F(f?`ArwkqjHJ!ctP}o=nU#wKaXcAetH|G4rj~7wypB+dFX7h;(a;TXvC(y zZL9hYvsppG)4J8$)4bI#8ktIOuW=x}JlGDwaMmPpc5Ajhr3%7`@&vZ-69Zcx!L8tt z9;7QKt{eHT!WkjTC~+E_D^xps2^4^P&P(Iwc(YSnt<6*T*3_4R8j&*&|4-yoXJ;lgZynK&+vbWLjkuhl_lRnv-o$yQfH#RmL$hGz2e{3-MtB)?(#81Mmf~Tvd1ouwvMB=8a z=JFnrGM%hB;zf}bc{MJ-n#GrKCPyuRcgkcZU>Q@Ef15yl8kMH@I$p)gTG*n9urdxB zT?u#9$U7E5F)0r=DK9PHD}@(cmE*Iq4*V!tc4hN)|MQqFAs7~0_)94K zhKD>Rw5<$)jqOto?8qPqNH=qpCpr|RGSpTGgYh@;H#wQ0IDVm;#X)#>+LsLt(6PtYsrHqyevoBcaxDlAil2ULW0CJRS(7L{EQ6k3-k zrlq20aSu7pf~^FOGWXvPqjexN(f)CI|8fj_D)ldIdQ`JhqHO=vMt3VA3orHcBrzhnv7F*0%l#)iG>UKQs;;7kYDD-9iu97N{flnj;4_ItN~xQl{;_d zNt-F_J&3~MXDe0c z_ASN5aaRjX3u+e=1z~x|IlRWP{f~-F!;^sOzuKgJlR$upAN-vh>*nd3>6--<*W15# zx`>IZiVWU7ekE7cgP+iK0fvJ_->r=y^+P|CqW)HE=TO;0%uE(Wty8`o?ZnVy0$N&n z<%isSW@1rURSye0AP@2*iEl>4#c z{LjQ5B{A|@9WBr5Yt>1dnU$8k+*4f>3iZ}hhH7iPJ(cL7-ciDOEl%Ts_x`)^l^MJP zn7Ux4JY<-Q%DhttgyimwV>bYA8qY51O9B>8Xe-~Xe@$e!w(Y|Ji=gkNO1iene_qTT z=@n&_!CPL(w^0Jh1*7P~78|D!*(AO0t+HbYuQ|I?8~F+iJGN;|14(IeVntY3+*M&Y z+#x@)gfH;-9;UftQS`q9PpW8Di^nwuP7lQeCIN$nUw9}}pJiRG6u)oYj^C4aNApJ2 zXJYeB)KjUfl-y&P=2Q&%{g_`=52aI@fNs&X2E{92Gr>}x$72+g45?7=j%{Qt;5(rq z%0#pfXcX>(YeKwJdI8eaK6K`w4A*#~{jQL+0mPxUk`wZwn;go5T-*H)T1 z37)QPw!M`92{hBS&FxZ}()uiDeWpAT@?{l*(Or_F{us$kELNc*XhMuR86em+kn{1~`QAIwO5eM>kmH{)bnqzjE$ zbe!7w5e82clAO1UySCJV$JllU`zzAE`E+p(#WSr-mVSizu`kuQHFL?*NyH~77w1@k zlt)Zil5-5Ge<@G_KuS9U|oP>N37LPrt4!#C4q)*B)MY19Vkq#dd@8k}`(2 z6$CrBWdx0Eb9nH&&|YPkTyp_mgZc2kpHrA0LCn8ha$l?<;tC)Ev(T>0LOM}Dbr#z9 z;zn*^O2o2V0S6krR6HmuTT$lTPpvj=6I$XU_L7a;7K`+xfU&Fb1rPdFWyWI0ZH9_6 zv4!%gPUU9#=N|4fQ}@VTgtpp3a{me;#ZGsbp{@Df!B+m>TjVc1d_fv5tle9$!M%n9 z2mg46g9%J~kAoOjIk14I$vv@xNv`-FHx~R)WP?ed$R={fp9M#r+JPvbi1Eem;knS(mpu+0I_H9u2-fE9a6J+dzk?NFNy+cxzC zG(*(5tpNSZha9K8X1%V{%0HRMU5fkOxXq5$tUwIFk+fqAg-av!Pj%o(;NU6xLcVe# z?MN7O|3Ym}(T+sDM63{;AumhOo<)V=I2@WS-*h3*iuwE^ZvGzPILyC{&yrudkSFpU z`MnGICFj$$qeIK-dUbeFr4}VR6W-Bp2#3f)O%$hV7$u&iU-429kKpvz(-;yFtqBQI*R1=Q&^@FLpvPXJSw#%yv zIR1eO)Mec+*A(FP_zep$apQGOap0(vNalh0?(I+G|AG01ZYc}D8Z=c)U694dOe z1+E;}r(G|cV`SKRuP@|lg*hei!-c#+(L3ArMLo9db}TYWF;`#*p@%7W^Gsn{Y#_bV z6?}0l#ckUiLECnD?Fww;e>GR$vjXb?bnM9$IC6YorTozfzBKOv*nEgn_?MqE3Hg>sE*c^c;;j#2z-NM65^yRzs`o-`qyd5xF|I2`t}$w?QjKkUXr zs-Fp@1=zTtxz+r~@>eT)hB94gs$f{eIhymv*v=rCR5vtINj>wkZ2r2Sd5jUPqb;T>%Y!UT7;pYLutCV%S9U@Z?5cbOU zi}?Z<7157Tb@uh5y7vWy^?n`ZFCJLTE5o{fGFNt80=@sMLtb+UteE~BEgsHeM*C8HA(dl(rF-xy z9_vd^3zTpFCGdBU|J6&Nb?1<|DX9>~wtX-!jlH~!?8QqK`o$pqS*sjdjC-|n-Cvi(xr7VMMHzZAD2=g8My%IC)GN3kSs z%$z-!@*T)AV>QpP6L0iJ3Y#-L4}2JR$5@K6ruyo_H)PU1-Q7%$)wyO_5-P_f3Ez+sn?ed>5=ULG-w>;bB z#5H{BVtsEW!t4D8U%VtML^QHsIQwtW)5&V7YnFV|8lLAqmyR+(09=c6o7lr}E_$RAj;d#I#c0%SHLMQhpI&#+Ce> z^o7)^LjiUtegnm68&OWU?Y6ZL>8&no12$jD{~%;vD(9_*v3u_WdCOWDLY)DeXzxPW z?zMc6v+Zql6d+J#(~MsSy@Ro{M3tU~PN#@%@}*Znp$^GEzKUNJa|k8ugI^)~{#E>f zRF&J1)(fxTjlq|*)Dc;{4%gIAT=w|G>v%LLZl1iFKg`$5-(Szqxm0Hc^9OIkI`>oW z$(z;d%f;G9lB$14Wsu?zD0#51K-noxuVcUb_w{`43_U91H1(Uw>y<%lmFH}L4yRrw z=WXE0bM!2FX&Q5N>}|qh@^u?9T<4|9cW=O{+WK@H7htF#1kwhI?xYDx4JZu<4q`H^ zP`=bJuuTi;l!Q*rV(}|VR(*=VKGEVwU)QDM#XIP%m~K8pUhRz63lC0GIDJRyXwrTa z6EZ~g5ZEiI1Qsr!Wq_n)Um0I}zRJHBy1NFttLi+>_V3bNOm{d=HsNOZlQO_u;P!I9XSy18z-3z=OqK1G ze1=?5!MB9VE%?uJ&sXrfPboKBEqBW%zK`D`&)t6Zd&HSp^>S0w$$A;wxHuF4w zqx^S}`CW4UHF&Obm%Q;BenrfK$mGoIXAjCxT*H^}M){L#_)Oh;#a8k?v2@i%w{U+) zHI@8JY|-$`mFQFf&QVjab_tf{bzTeo3ySydvRjt3X!*G+K6Ac%J3SY`@yqt}Ao(Pm zFFrcY%{p-@+<71yh%c}lp!3dKWWGh=*}jGEO8gt$!mqOlue}%M{rN30-K~#*u?2Vk z!aMKD%c}Y7cpwsUEtkP3@gncLmb>tq5>XKReWDkJIt7)_W%-L}akG!%m!szA|Ck!4 z{G=xK&@Jrw#8_s-e%rnM2f>`}a%>F_FyPa!uE7ojcy|rIp0_-nu$8~dA=tmyDonfZ8cD*pf0WnP;iB|+ zf0SG5uzKB0iv!*$kZkF4!r97%OqieFfhlwm-`l0I{3^=K&}mk-cbEPQH&#x#jwdM+ zgt}&3$5+pyqu=8=GKPbLu{B^fo8P+qtZT#!`Ht)Og>&>|dI=E)%M9-jS^k791>!RK zlk0c}`6G$fV?15*jo0%_$ZEZGJ-Ua5_@nFjJAAMF^bdGOg1YdI2p?+;@6GaOKS1uG zqjFw7yoeJ=<(hiFCiT6e5U<6C2^J-uK$vWs)6&n7{!Tsj`TIbt=1n*(>fJ>qQxzx< z0fcCA$n^L;bt5|>TnJ%ai0^B~jpf7cF+8joQ4R~7?tX*al#X(?5SiZZN+U_Cbuj@- zg@4&$rigpn3?{N?P>3FcsizN4_lRIO;op2gg>I#g{LT+~dNQ3%M5g7cX|Xq)Atjm+nm1^nuE-U!H#x zU+~{5pSZ=cZOgS#tKws1~?whA?G5n~T(k=#vbcjNT8;yBl$;qejyOqx#=;jX{ z=;HJx=!ly~WK`qw;+y%>WMYukKs+{7_D`gcSO|CA3{M|;CvZmO_0mIVWOC9W!cyGK zm&fXTh5MV_h*<~Av9yuz$kK0oME1}D8$4=!R|P-baPWZTL;4Ne5Ik)12SUQchw=xF zJayK&BlKM+_y+JTU^I7S;L9NB_5OA_;m3TJNxg)7u}&V@BUs6YdFIF1SzIl@|6~3y zz#BVwhQa+IlmB^zFhjPa!3-|^BR|X79Aa0?^ZjtyekEV+$FtGz%TM_E0^_egWG1=i zdpNQ)26&;++$gUKpub&>@|FN@WBqbxfM+D0K&~{#_7k4O$2$oO zmYrAUTz?z73*wWv;k{~}eECn| zoTtdw{*+(Av*f3L$}i)WKR&$~>j-a_?LWg21M;r@8PA(>HyVi!l`>)=3XM1|0U=%f z&CmExXu>S~UzEKKT$IHYKmI)Ptn9KPE{KS$;_kAn2#SbEW{7}_N`{DLW=d#gUMf>6 zL$B$oWTu2<=@Bw7lA0MIS!tPh@g*}WGc&WU8F_m#GqX2SGx>ebJkJAb_uk*{|M&C3 z*_mfv&YW}R%$YN1W|qQ>li`T*M~i_2RWFJaEmgOvkCA(sI$B&hMYEQvv&89BbZ(hC znZx`twN5mhBJntkSxad6<7%(=CQdSB4SKI`r^g>xJ24!aA6K1Dv$M>?hgz|rXIow%k|z@ zEr+>@iB|#iVOaZ($j0WxyeHHo2#*C%U`a6iE2dL~cQ}3dgxbMoM#=RAT#U_Hl2)jt z2G%0!y%lN_e*t+4#Qv|S;7PTH`3FFXZLv;?|-r8-dULbF%GyDovA zS*Z@&uk+_l$jEnQ>Q;BT?@g-SAYUjK)6~`Kt}bDygvHHZ<;CS@V=TdAS2rk;+cPUwtE!Hs;Z^FE zj*l2w4|MvjJQlvQv3_0_zPh}O!k$(?3O9)urXkO$ea3SsrU4^jt-S>iW^J4v6u>%M z8w1JT`RMkQrei*_4*L$sH$6D8JRNxkZap$zwM(_YSYf-QTbag5A%Mp;FasX=mfLrD z1An_$&kzkZhvKf^4gIAh&;LpfEYC}%fHDc!R2=ZZ`=6E3+O=wA?tcU5ng;5xY2cdr z-K*Ct4G=Hx`b+}|S?B!!R_C>_?E6c(zak|NSs~Z7$@QebuSai#SHQNtY3AEg9ibcmWHk_=ki7?MRA)46K51_DGTZrN-)BqMUi+`o!Xw` zoNg{8`SQG5>EUPL2Y)MFdKMN8Sqtn#NjRYD#sr*#i_-exA}`dCyB^Mbx6-=x>gb+V zQ4xD`qyr6Ylt~f%o0rlo43d9fLCfw$nBRf2WO8r7B4#jUZh+IocPM!U2b?jqVAq>e z_uXkK+Mqg7@gp15yAb@aL4Bk9-@d~{l4Jqh;U=ME)Men0-FKh(4rBm$Sap}9t@0=6 z!;R`49q)xo!CFg%(jIrqwZqkIW9nE++(0)yr`{dB1+_5`ZK2)I0g_wk%jaZM!#81C zj-uV0)OO+AalVq9YiFp@;cqr!zCu{=Jm#lcX~XldI03%r)jn-ToZ%XU_Ya7m9O}6l zOW0d!(q>5JztK89_VH%*U+Rn7UwT1(QdQe+AM&Dlhfp`u^IL%IMHE|)HP-jv)7W}! zRe$n5t*ys-f+%YL5@fTT{`L|ku7lsx(w9Kk?~REoaFftd;>N1qp#nLOJgK$qTBZ&dSW$S(EU;Ibcic6|Aeyj+dqMh6nd-yxJ;oB8-TIS z6t-IiqjqCTOQ8pMtG5TI$bxrxQ|R;E>ObQ9pVwjG6UF8q+hmj(gJ9EdaZ|L+ppARf z#H=9Pe`c9si*?&n75D#mkq+v!Jh6VvfJ=0n5Ar7NQxl{4 zyMA-ULTog-A{?;PeJ=Ycyq}+^Ir}gXgZobHgL~xw>iL#>TQD z=*UOn8GAZZGa-O713uf#&om=T?X0#X*mc@D`Di_BMA!`}4}mPRL6%uylJ9YlazBBV ziCgE=f?tPOdnXQ@#!^@#PLpj^>FPnqgI?I}#s!GLn3fhbb29k9g%5${)OX=Q5jAsC zt+|okd8WCMkFz+A!|Evd_+7O_bM2Az+q;lOsNMIT8n40fLAN)m-6^FL(Aa>}N8nuS zKB-cjvUp9P!oUYi_kI}rki5J{Qx~GR(fdAixU&d1G^z5^9Jm0~?Nm}Al09_^P=8>h z2;YP>K6}cpUWb`)aq&I!~%7+a6^_-D^r@-789mx>_Z=j(g#ulLJI} zfz#L`HD@%YC9_}PVD3EA0~>E4NR(OTPyi|ZH8pL3@UF(hl?6mH+w)}ru!!QH9(UDZ zjd?X!M3VoIYQY&f#j!h_7GHL8&^KARlCw>E13ACw5{r`FR|j9)xfqwF z898d*ujtfybSki;EghsK9|UkhD82uI+AV@{)4E<&t^g-yF)lK#xt+GO;INwTKQpG% z)x&CHbM6r8`=J`+;A$;OSWA^NK2-D4OoE3n!TlMG9Sl0P4kJh&ExT*;a+NKdMde~&%0vqk}DRk$@ zn2`t2=O07ZnGL%s^OzblpoJki)WK31&h;;WrHChM9ufmFB*wtkKM%V}*d&Ay3#-%3 zXD$&z>yD}2=+l;uH+_O}FaUdj%m|R1a3Aa~bpqW`1sRBA_8?!{ zl4E2)jv0chYeLi5Gwe3sPFcq>3-lUBQxS%9^IT8GZ#pkj{6%cl#w#0WuumP2U$`yD zvk=JH3@C>m1CX9b<=0+O<`u`Yyf8dfxdM@ zZAUZybq!zv{6e+=g4f0X`tD!qz~=6>rrsyit^qv>EKoK94nYH8?YTC4CtRaq3L)-% zOObKS88LNyt`5=%%92USaWG9Ymg+xO3!5`WQOA?&jZxgy)=M&F#!|I?OJ<4E+LP)C zK<+*R%sajaphh^2`T~YU2-!Jbs7@s-zc>9^(nfrtn@r|dDXBvHe3RY6=rT<$U>T3CF=4uJAHr4q4 zD+4zE`x-jy!kj9;!FnL$E45!6?u`lBL$vNoXr2driGg>iDf$@7*S1j()4I7WZAE>8D}r5%m0NXx?J`pQoW6=~+gK zZI`I{49vmYn!ya zP&bnNST><1n)#DD)V`8Wm}B?#&{f*=6J*wSmA?52Ymk*R@n`&ObaRV!*z=-Z3x^_<|j1al%IiXB3t>2H_RUfMoi>tjlr!)D0~3Oqe)|J3 zwUnXsD{5l1KT8DeKHNyNufUs+Q6C93T9k0i1&;CvT=WhQ_Fqwb_6E4B@WwjOcj1bf zWmFgBMLg?IFhdwU{3rBCK)UKr>}{seJAZ=N)98mkv3OWXU9PIVf|&%&7UP-j?P%In zH3iT;b5$KJtK&}#6}o&CrIfw%_{lOVQP zU1KB9YqqqINl$ly1~z3uaw}t_hK2N0mBKaIM@rR1f9_SWCX%g8BeyGs z{w_p!gSB4X5=Jiy(am80m(d=DT10gE28HWyg{fFy9I$);X_G$9Fh!J`mr3acmqLcq zi=E^mi%8_Pew9Ud!Wm{J-X}^!2ky%#l@6f|mLBJfFtn8(hjBkgY*lCu$M-5!)k-+I zKigV~+~#3(QlZcwdv*{R{#X8}`$-Ad!sq&UZn;FSyGp5qlGY938RS zni2a%Q#E9Q@a~lz2CWVK%j{6J><|k>{VrTq=BGgqL+AEeMLcT%$tn^+#4a}R(R|ZB zz#(hxuHwmME;v8in)lH%y{_Vx^^v#OTptBGIt!E=ge8H#ifw9|gff}e_;$F8*{Ql^ z?d2_Yd;JbUcLa+8(jT+F_}cq=4ixLl>Gu$RoI>YDV{LKbSv7*r28$5*5#S{EH6=va zf#OU!GvJ-6;ycQslo&ZjaGD=C^)$!@NQ_)uA1qy z`YEbQ`lrKp^i{jKE>>?b@J1rspoZF^&3ol74AEG+Q&?-!ZrXw31-OT9l3Y4*7Qf2` zzzYB@X@`sT>+=<*Pqq9WXMT@W+_nV@-(vgU()qgn_lgHKUxFkT$*|t&{`rSXJQe2e zqa`gzdyX5w50|(r`beq@uX*sl<&ZynQ-}~qk|63GBDw}OmQ0RqETOR>Vmh4NuRV=) zx@1cA;gZ4CM@w|qy5l82m;%(avqtDt!*qZPoMHZ8QjiZ zl8HM@bq&B+?NUOh2##KY(>=eI460^$FP3=a>f|-tEy|)}bZ^QJ71Kj`k2bcSAGb^t zvb*o0P>~$J1pctYRF|YF99E=Pyvmi4d#7TAXQ+th$> zr$J4yUect1G~geMzplrGfV86}KAaogsNk$Rx7S(;f}Vu6k@o|Q);ff5{Na*CEAUoB z(l`TK-0{JRN$g-1*JNCF=>!n43We`6|O6MnhreO?XU2lhIT!d*4sr|2+| z73rTa`o$o{o>q!56>c#68%UZJCQ|2r0AyHT4&ct&uL0VtcO0AEoQILa?eTB0wgHO= z9I(C|SDkfZ4{`Ruzq_eGA{BQW$ubF2Q&g1Snr@K@W=A{jKl^Q?uK6+(mgYUYxIX1< z({;@T4aV*m0Cc#-FOhJz#9PJyfaA+zqSh;W+iHr>F$q8g0SWKmTM($Vzbt0;I}kjX z_})(O_2XM=Y-ut5zEm>NMjO<}tevTR*+cKF3%vp~0#Mxmh#5O3g!sY~Iv6gZ)ot`$ zxQJ=5BRsZ@{du_mI}+8I&)dT%??VSe*h11n~mTp_Pt0x`;I zrN$XOzY#VDP@BIq_4#IFoqBwJ@0jnas~<`QbG*^UFzL_Fbj$2iX2C$!jO!_ufK;wr z^Z*qtnLyDIm=598pB^EyJ)FiXXZ8ua0y3LY3VuIuLou%-VM(*t{kB5k~p#=SG-Ddy@=%ONS~ zey0cvfN70W*n+P&u6Y?kFFHjp@rjL2Iz^;F4=y;Nhz%ikC(*~wkjLWgA|w}d5+3=4 z6eIlqh76N9t&ErFKx8TS*xm$U)-i$k+DwZ~*9jbJ+^T^ii_HT2T0%+&rlw9}lE*vS zyMhh2?O`!?W8)zN-3&KQ3Np8WgBNxd@p8z<%}&8|ziv67AcO%B(pjYSo1Iyf5QTSp zXVan1A{r+dTOsY0T0W6wQAX98H{`ILlsjuu7b>ERbLTnTGDi{^1e&$|0>Yp zAkctc2()POb`_4$I7l_~z7mY2tga#*aKqot&;fLhXMKt^^#W7*;e6ch^Cfw;XG`?0 z9hR}DONLK&lQ< z;CWONn05gO;VHDOQjNM4rA>2%TACkMTEIgjf`Kiaz?!@&2~avA4;tW|wbtfoPl08I zvNo&X(l0h|Hm!0Aw!XdZ5;0hm{^Sy!JiLO72d`j2q^01QaE5Nw>~3D%J>D(W84_HkmKm@nHaHAj9Wx2yu#z*J~GaD1B<_pnw^Y`%cNQ=@m4W` zjv-&}v_&4TO}(}3aFc$bI7A&Hxq{`wD9pIrCij`!=eBeh^rvV>&F*c~snY^=X2%L& zvRUWL|BpI#xVR2l8!Mdi&2rWMk8%vlxJ7&oQC1Iz2fx8-I(+{PSBzIHICR3Itcq?9 zxL#tzmDLqoww}Z=@b6KxJ^E8QV9j)&@T5;!l!U7#6v@s|y?r{cv0k?3@@@!9*Knf~ z41(;&iau|)OA@N2l-Bx0Wcu7vzERGR<}cOCMbe}h>v6-su*J;aO>Va2He{v(oJxI7Sj;fRO#pcm zH7Tx|Rd|Iwh!%7c?QpwW5QqrVnrbW0oBek6ghl@9!bOGEP?NgbD>SuYLVoSIMZ8FJ zl#iL?s(Z_>h8)8iOt}UgxXMUW$LT==_h8TQlo!J8@GCvhUGQNJ4SYBS$3zxjGd0`G zPZxTjfwjW%{c%b#__P&|S6>{gF9?g{L~4*;hU(%3-zs9~@5kaqd~$EQYTJYPgPUxH zGqz@v9Dm6gBb#O&d@E4JqyhgYcNfWA@6_%h9djJRq90iSpGY`ZPcJ~7j0WV}-(94J z>1FxhdxjNnI#Qc>k-*jTj~9FeG*?6O;)N5xCHQOOMJ|6o7cclyH4A@FOc0Uy9n96{ zB#6{eED*=d(XB43vJh2UK%^jVI-22`Y|I?-VuaGIT7Uh{TRQ>L-G-AjxQGeZkF8~H zV$OI2A#W+&NgpPNKJ!aT_eu8wE5FrKx(*xaz2)-9U%H^&uJnZ<(|%N35lZs?ux zq@qPV#PHk>!TJYA9S^N|L#*nfL0{p<8j2|j;b3f7niUEzzi7ldPAoRlLk%@xwuPKM zg>x!vaNL;r{a51v!?!_tI?wd{-JI#o86NHPjRvyg6BcD+QS46o($JY0p29^*6{lD` zM4NBgsj4Sd_YgNHdkP;k3k&G*h!l6AVR#}e0H9x1qDbdks_j%h9seCpQ!V6LE-Y}^ z*L?%Zf?Ii81Ae9p+J=M(=Z#Ba=ZauA*v#8ib=hK}bT+eLpe_jx!xpmYEe%$Y7ta7* zPdP)ybWDJ+4;8(Jvm?0$*OBlbUZPRMM7xx7d}YdV=ho+|yRZguGqc!Fd&)|9?nXNqLrfLaKsnNykjDlm*N0&ttpOUt8_t@Q2y5le9+ zM2~p6PN?@QcN&W)UQDqIEDmm9vqOhELjIwbaOjS&>7@0(N$Md^#ZwsibifL6-A zS@C2m8xtZUVuHKAwa<{e=Iac(yu{pK}=4PrN zE28XrJsBdSEzKD#at#gM4{ui4*0Hf7J8~s&*8=gKmDF+r(s3z@j*b(<;>}vWb?CAYs~Ob3s7%4;Y`C#)VziKbt4K^Y zYxvxu(~@7)eXVo>TGb#9G_=}sgtiq1ahNhliX5)va4BuQRV0TVl4ZjsL`eJjRtQUk z{l|-i$%hT7ZMa5L!5>6c8Rxg)_r<3CvWDt*a%0K=d^@T0S5KgGU!?I?AMm>h3wr-s;&x3km%)-7izLi-Y2k%{w> zTt@E~UrR`PreH=L5k=v53ST@6^Se=w^RNTphiG#;;z3HL1tYn+{1@Rg`A!J;#&&e* zP7!HuM0;$K7VYTVonpL4Uc>{O!l6)>GjEWJX{XxUt4HJg9V(hCqQeppSFsA=5CYDt z(1Lwx4DFmMq8JzH(}0UX_!fYRt5Zd~XzW1gcL}HSn{c+p*}Q!D8^gy2K8785_-q=S zE#A9J*qkOZ%+4>6jmgfRyNlHcqoHU1v!T>Lq~`@7-3y{|%GL^EKu4Gj7S^N)oQ@aA?7R~bvqV$I;+oLAAwidC(?$-*tfoVELj}i0D?i^2 zwYegKeD{c{9v)z;!5l1J#;oS&R5Q!3!r`7Dr02AhN~*g@ zeThRl|GuZvRl6QmVY?rXSRj7M;YOVT<+HpQxP<@~wp#wid6O!WP)4NnsHEI`MYQKD zi4#TXQ8}pgGl{1=ydShz`EK=YW!S%XI)cjY#qtXd|3~f>?`Yx-&RmPrE&vARuCZFi0_`-c9E(L7XV3YPgqTf#n5ID<`!eV1O$tVMZPl~ zdF-yC63Y*uX9O&A)AzKepNqvDabqM+zaR7Ajo=bipl>qv?cR;i^UaK;y8F?i`y*-p z{TNjlsTBDDw56vbDVswK`B@K$8s{mr^DTCY9r6;}42YRRsJ@E$K9Z6j6zTTwQ7=2R zq1>DY#o~C5^Zfnqru9DTd-)*Nd}iA3NE?i_VKR;4XMsy^??Ab;#Mt@L+!ZH;JFXpW zaG(n(^xLYgE{XwRd9)4u9j*1d#EF)D7$#Gbi6a}-z zDmxcBgH5l+*UqYwvIvbjY|(!Z4$WeSYeObnaU;B>x-fXxN_qo`oMs0*(^8O34s zK5mqGI&yooA3M@wkCO@(0N3|Bw=Y~Eid6B6lg=%Kw9R)?TD2HnITgUbVv#;}ue?x55uH2n+%dWb@7>;LT=>p& zL5R|^oUQG#m@Kh@70K>@;l@pSaA{w`CM~Cd`4FSrz^+t-x+8}p9|KZ|b(CrM!)oxt zVv(Duw~ISdWV`u2SXP%+W|s9bR=yeU8!z~C=h$2DfBVnvztgefr~63!{pelGZjB3 z;>G-ITKgEp;e}4L?J>|9Ecw}E5O26aL3YyZCC^gi>)M%emx9dUU1{-Bk#32_cXEsr zUAips1KtgOo)P(u&IsJ(;x%UN;?5+Np)kf*;xde$JIVk9!f(pN9M89U+jV~(6%k#y!@?WUg%&<8rsoWM+zs2jNb^3Pg;3+?b?dyC zC6zL`0wQdM{x&RgV^-B?SyK*RaU|sc+bTxjTd%IvzZ?kf@1^PGqR2Z)wlk$V8`oa} zSVfP+7U8N^Mlol@CP9avh3TNna&cW~fy|Cu$dDDZoV;8lhEA7h`PH#l8;$BpYnMYQ z(itX0Z0thwDljZT$6XZ=F&kp&B;rn;{%`;_>eG}4gLf$P36U?}=t4`MfO+PxXz3nJ z2cHnz?A@bv^dP=;g&3c04qU#iL%y{JQn5Mpw7k{Jg=aSl!+8Lkd^bv#$I#$+*_!iG z{F8t+DVmC&6vvXyK5(6Pm^Y1qtiiIbLZhw>vEHcbj%X@=N~9+)lQ)p@p)QA)pQuxm zDRFieyGHsYDa<~N#1ykDnod3?ibZHw%3le74(UouR{{noqz6}utk9E2-Hh*((d1ku z*1CAGvMK>$l?kQLfj6h?Qj{6Bx`4^6<<(&42v)UNJXch*sRdTTN_`O+Wn;n2sZ7>L z+^~R!$3tCJ9EPiTvbC3GHc)5FkTW9Bk`7o<#&@M11n_WY&d(&W>?@IVT>3aA@MFgLAt)%7~~7V zkv_=E%c~*Hd%DO|iQzxOMcI|$R_M}mDn+z!2J*vP%Og61O|VI9xk7n(eJzKk4vU71 zN7k-N5t*8SZ`l4u+w03Ww$=4bQwB%7ba7&m!kmkuU1YBk(aHLE2SyWa&M;)7*_QbL zNMOB?9OJ97u){@q`>O!&P#0aU0vjWq`!w)Y$b2|D8)WxXR)rE z5)tbyQJ?D;2l9t!26^YI>zB*59p*5z4&3PM1YgnHYebuLUX8Mf*IF4Z`4&%Y!<(L0 zinw^dK<)tpkukP#g@1FSQKEVaR>! zRb0^Krs?aj`2P$iVCRE+f4WuM@9?QbJ*hRA%vetg*Y&iiHDW3o*bmi+6+F*Oepcj! z^LMzrYPvp^p%i#%*Rx`?R1AS_ju)>Ni89W53F4dA15SjY8^DcRPS2-vtrsIN#wHXO zR(V3XqhEmsilie(Dw0Nh1sh;q;Bu^ZqMmt(3r{avwE?5+9NI^{4ByEOSfd~uzft4{ zXT`84=Ba*`K72&9AUi$V<`Q3m?^6(y=AA3r4KWASwNgkRfQAzJFCBuRPnrUvBI$R zd2x&$R0y^5-OFLdbhyLNE&t3rj!@F)zuN8J79I=#B2Lg4A)d|oo zmKN4QO6Moio;qM+Oe}e}h^=CKEFIed1>)wO7)QTEJ+`(L+I|HK%)LH3`3n5B z+&8Ns=jU6~5-J2He@p>DrX0COy6(lBtn@TgQm@L-@Zf4LepCi|Ar-KJQ7HW*LdGz| zk_HxHPq`$q#dsT4#ZC)Ju;tRO=`e-{$%k3 z7P_!=_I+0me`h5?f6L|w;T$Gn%^of*XLjjhMEMHtnwOBz%~8C-^w zQc^O+&Tt7w965JD%C#Fx**iqEvkrBofbgp!CCV^L_&3*C7fo#9-&L-Zf}I0(W< zOP-H!;onTG<~}zHi3k4POvI!*CZwbl7}BIw%XcO+CB6a40{`62Z$NbTbh==sXB- z-;2J0@#6Pl*^YQN;!cwRVv=40EDh4a%_9Qe=Nb8#Q6o)8jR&Ll1LGUadT1|3H;5R& z4|OBV*(W@qGH*ts%m-$gvkyi)ZvQQ#{kMcOTIMla4A`p9OqhWe`(pcHFeTFDx8S~} z!=_+vIo+Q}w+s1(VO!cPYYrIXZ5~JrpOJo&+v||9{pwp-dM6fu2*4i9aMOEND9=Mf zdjX@hW_gK`9$T29w4_nN+pzSNB+$mU;jpkbfqVxbgEuGOq7Jc(0nB+v?@SSgh%bFd ztQGBgQ2aq4ziSW5KL}Y4WG_AlpCyDx4nj;KT>383f9XNH-i6QI?jAJtJunv1Yu?kP z!Z+{fqTKhshz~v4Lx=f2z6}+#vHSc}lNo3^2#Ca9G{AG)Ug!zR-2c#ALg5g62 zMpPNG!8$Pyq0Ib1BI-y|ZLKR*aS_aANRMj%t>Arty&WPHPP4%F81Q|4!0*6x`TMWs z`u0?9BbD}Er@o+~`wofTzWaKDd%^8Eq6yEKeBbX)8If>D@?DS2DpXu902OxsAt2=X zo@D<3{uejl8xzm0ki$siGea)h)D+PiH}eIibG>HzUqjBvm!g^JzcI;Y7m|iCjxNZ{WfO1`Ozk`oiV*M7sJB z$c^=9|D#}wTCm4aF~^C=!!RET@1EdR%0J=h*A;J1b8oLElJjFRU4G|N6{b2k4igcZ z1M$7)V-auX@|yfk$3BKxuoDEa8#_<5W`pP~I`*Qe$3#IWD=WP4X9Y9mO*(Q6J;1_S zd?KbZM8%&#G$P#m2_%nn`1Jd+gc>F9s^+B(-)PHF=@L#sUZ$f z>e%Fp$ohKKNo6y+5geUsmfJ#|J@O;}3uVb(Xn~+3n|0R5x z>njJr)>J5g=fjHYD_agLGB9l48n-$_S|Pd3O_gq3uj7*W$E_ZW8>iQu6rIR*LPS`2 zzkp_ZhNl+tPKXKip;*3fKkkDO^aKX>J4tlrgz%*P1SOl(Cn%$Qx>?dCh8uZt2Tu7+ zC0SOFdy?w(<&H}PUq@M=i*3;n5`0B5>o!9M4Y-Xw3BfeABNdzkCwlwP(vxDcZ$NJy zw+|R?n011u>)7N8<9Ro1g@k`0imzurz{x~odnU8u0Yitn;j}h4r7}|*Z2N<2E0*7n zC9vKPMae3&(NAB94$gk~dD-w!F;}AuT6HCz`vUT*tdc?-;Yv1<5*xAHsD}xddys+q z%#0o^Z4{n(<{pNkrFXh+&U*KhiS9DiNcs1)iFB+HA{9Nq+KBnB78v+a`1;p^NHKo5 zh&j(T4Sss0LF1nB!gVw+W|c^92UuL03jacQE5?V>{;V&-`KV_j!ukBroUmD;!sqGS zU7w-g+%)F!MsW(R&^YFaaysXm5TLi0?mcbru@a zu#Z%O1vBq;ytKuK2i)0ycl6!C5CXq;jwXwe zf%TK3>@<-28?JoS5z0@pW|na$AugdoX4dXO9vEP&cP7)ZuY_m3$(GEDgTaa>(Xq8G z>-5Sw=ek-Z6bnm>(h$yVu|mSH@j;;y{4K^2eoflYB+CC9%ahefwCigz-p;VHn{wMe zOzU^+77lIt@eMF8HjlNIcXuMlwy$lhtfcP%i2&JJ`$-sRCDRk(2 zQODosorSzXxb-YM&Lf`#rgaY4#BMrx;dPvfwu(CmrgI7C^#Gi^b_8(#Aa>Z3`*Qxy zUPoU#^aJDxWYFawFdsx*M@8q*j(MQ-Jijy^i$(voO6$z2zC2GrG#`MB!*&I?k2yq~>ASuEc@e3GHyVXapvU#4$v+8? zEvGjF`$%oGY0xf4_TFCilPJI=5vdgV3n-7XcXNJ$W`&)~8~c1ZHU^{rsy)ZnZa6wLL*M{U}^C{5R1d-n4<~rq@D4J%?S;B%nV7Ls^=Omi{KP z5?-myhQD-!MCL1%c|MC0hV@^|yu--gJeQjq=!5B^i(Q{!@bGvgMPC3w2y={Z)&*!d zi0`-{mWpxLQTFd*3&iGy-!Y||){?icqxg$rqtmpyynUU{(JgU0a}k7hcBF4+2_MVAeq(9QoN_m!=&WVon z)g`!a1ofkoW>#LUx6C&Mn776g%>!( zXxkMmXb>j<33r<>`_bkh6~ib&FzmtP}32y`ts@-WZ*P{pYOm5U7OVQlW#< z1Q>f0-|E`-_5MxG?9p9iMNd(#+(1V(%@fY$VxtN%JE>`*iaTY;4HRV2qR}q-ESk^r zHomux@?v$PrY*;zS#!1w*vXPwc$5}vS3HTBbIm_ zit{F+9M{L(hg;iZc{7do;ZYWpmHwb7wu`KEtN;?Tgub;AT2$I+gpeU z@>PRf~-0JY2pr^58HKu7qeI0$et|-1+Vx z=)wV%XwxEn|42i5n1mRC?86m+#6ZFn*|hkgj||w&Hn=XGSeea)=Ie(z-6_Sh+7Q-*O(TD9Odxqa{`I|ef&T(xOge(5Zo`v#I zBd^OpXZJzlk_YQn1Z&x-d;4c7r-{M=bRk4b6i3p?*G9{-zkVYgx`7Jybs817(WZ;0 zG&ukUvYQX%%W=vm zFw^<>J19Tw?|S)n22fC#mha<*6r`!b`FL!b$2s|kdaU2C=*K!~UYJ(r2~P(Z;xHb2 zS(GOSF_bV#R=^mvx{&iNACqDY7{pQRRaZ z5Uy*iqEqd(RB^nLoDte)-w8CrW%jlWR$?1m>RFsgjUDDv))?tr26@j!XzAiaCB?Vb z5}ic@xeQ+kzQFsmarXr0+gC}&?Li6%#8vGfn4TO&+uEZX!V5@GZv>1d2QnWuNIr_K zE|jqT8jv0aw*#{e4baHhb;=#LPS~nwY^1hW+%}L-Mryh9`CAMKjWcxxaz zqcoqh5(p6~ZXnUlCNwoR&m}tsgpH5VlEvnMR2~Ih-JMQXqqO{}-9WBA=}V~cccQPp z3Xa1}g`ManqI;OFTHfEjw^u8Wd1E(Vuco7x?(Chxqoxp6jz~-!9k8FYVR=*23g4)7 zy4(>I#WaxY)Mkm^8MN7{EuDY3GRbgY!IQ`aXE0m7H@7#W%qXc2^BUs-95Fg5nKF*w zve#iooO^y0STrx!;P?qi6_FNFm4)?4CN2`lgt6Cy4#UN0Nrn{T4`!(CFm`%-@x#W6 z{HG<+{!SR$@T?5&tR?iGcqbOo)egM8vPC|L<5GlO)j1Xx^KMbN3zFMw#Lg~y5SR^#V?qQYCuuNGCqrnyK2}o14T(R#T%jkCRm%pd%_ zb5#257CGOB99i*8#t#f=MN+_=ri?TA+(UKes6 zNQ;fgBSNa^m|KgFzYT5boex5PTA`!WwYI7T_-oqGH|0eu4tWBm7Y{%zdmsQ1PWEVt zK?Ac?TLXOJI1PO|8 zz}D*d+*r$dCBc7dDhxYN>8-8Fq_HvDcrhi5wsN>MYkR0y+og((LE8_-YT>FFJ%~>E zv^io0#!NRYS8l6z(;|f*uL*b4;@Lv+b2s$5Y!F4pX?4OrnD)nMKAt?z#cAW?BL?e` z@(afw;y^JUHQPMMgdT4b$*ot5_v|1l?yh|%5az~f@Op}*rSaP0By+tp8ui3B;-s}a zg{}xQZmxIu8y3VGzpE&`LuhOQ$ToT~9ZJyjt?y^sN?*sT3EEU!4SWVL9+W4O&P9;F zhZbV5Lke4n(Cn%n+FD*7ruNiw<)%5?GJhIOKkCqZTE1L=6uZ6Izos~^n`)K(hJDY-1wDiOh ze#Y1DS8%Xb`XVV1kSt6Y3)%clYO6KNEqEIF*=#CK(Q@N&=5)AX@t9_r@)gIS-mqI1 zj`b)Ot^?(cWYd`xVDX)7viH?;Y(F9&vn{#$Xh{Z$MZPveP4>w0o^R3*G%=)MGF^u{ zY$!#i0u_LId@7Lq2;6B>wdC+ZZdqR1S+iWhHX_o+bzsveLn!e&49eSvP{DOT%b20G z80p!!F+24ugyhOhVj~p~sv@+bD!*gFC%liyHamEg|M6STLl>^oig`=3sGqi0$Ho$W zGd3i47#sb7jSK@D*s6>fO3Bx2*^v_C$j=AdC8i(|lR>WQp>u(3hpyM09v$;8Xbmk7 zQiB4^gNH%6bf_YD7}@)Sxx$Ch)j(BV`xP+REZZ~gGi zUHyb`*MBJP!6U%2uQh0C*m>jk&<2Bek;5rG15yd~P0zrfd}BC;W4&0v-rokRVz^n3+bT9$CDclI5cVXW5<7xU4oBSxr{{ohCvxauj+UN`hm6t2Q@)lqBI;snVG7sV zdP!dera!4zsmcN$n3^e^ZOb$2r}`DR1ZU%o;Jf=q(4HHigQM!?5#ZNFBWURe z&>Hd25D$G(Hr3n5jvL4DV*5?NA$%-W+@x*u;BjMUv0jBk9?+sqm~vHvhrQLEWch8> zT=z{>lnWt&uqqdACFat$TrJgJpQ|s(Zn%jq7MPk}NcoS_MsU?QAY#C&g@gT(kjO(=^vgK)=MImH(p0?C^ z0(Eg2p3P&UGVn`yuQavt;`_lotvvJv*#@7PflE>qO&z5r+J{3$!}`;UcGix*IAU05U@v%MmplDqrvkhZlXD(L9#KqWFMpD#J_Iz_3>PtSKYQzXm@uV+XOjn zhN9HKH!$t>T$(oqg2_zd?+l+AH~S4z?m)dfcLm)H-1QC6tR;`XB-?Q` zZ()Xx)Z6viW+^dI*zNES!t^1+V=4rX6@~H3V=2awjOEHgVKH=Uw<|*Mx0tvw5?^S? zJ{AkjLHtayc81%ZcZ-%f-;es)aL&H%JocWK?X@>HGZh(UG~q@z8(X$Rlx^mTVuFhlQ#?lTYTQ-=E;l(~qDe;Rs5eWb)RoOhqrVNExQSgbBi%%DW4!L18aEXM$FcxDIVH z0yrPmWGT#~dc8?yGR^oVaGTAzJUTW(%MNE{j$I3l1ro!XI1%`ODm8f``qv&WyG+EO zN7%nWOO4hSS{}doda%iKdRsVutF`!Mv!G-d)*pQ=(2}n`Ug5|GDH&RZfZ0sWn>6@# zt)Jc8Je)R)7T>PrG&_5nXKyM2)a{VaIA9Z02+qbSklaG(d*T=ls@%Z}U_Pz5Lrd(x zFCVPuUx#_V6e4Fq9QIx$Yn_Lvg4Ffu-&N6B@yj=IEPpPX%hzhYnopNeUhK=K_$gX^ zw3!b|y*DPwt7O1<)yAj`d5WiKzECp{@9+MG7jLF$o3p=%+nUtoprK7`YLNCBPO~9T z2t0Re%1g@!14eg6zQW}%&Ud5*hB}PfSKX<7riw+QsrW9i;N{V@_AbpAe|a=ISCJ{q zM&4}lNAjwxrGag-f$K)oxw}BZBcmyM8kD9_N7IgJP;^kweLUmt*vXQIBjGp==nTY#5(TTQ_Hfs$Ldmma2Zo1otp_^hfn>BwN;{GEFCFE z=hlv;@cXr@(2B7o6~`3h;kC(>vD+s-UJn)zvxkYoT zZ_wt4fZ=}sq@^VY$NZDdaJ*!<9$&MY;yK-RNX9k)2ZHXdLBfZE5?1Ts-AlCSpd(zT zO3O>Mj@Bz5al}gZAtK6-l6|%otu=lnXxTC?TK$@eP@`7=wV-z|BYp-?#Uk!MBk0DB zTD0|hEKG+Iuchcy4w50j*V_AvT#n#X%0C?-_E*w*+?Mmd0)`9TP1rWw>?vz$- zMwb2M!|`anQq9s;0u+shHW(gJA4f&yT2~P#Yh1M*<+=wT!evAn*Zk!}MqsWyGZ!Pp z{IEj{4(iS@n~WPzMGL@UB}ts9Qm@tMNbi7-7{9qA*6QARrjdWwI@*RMa|DFWn**BK z`g2Ut8QNMcV=9gGqqhD);dAKJ4Mq>11PC{9ZXE>cFkB(cO>?cHEDh&|(DMNSAQ-=ek+OVMkWyTCONLCt{x*n-_e*yt9R4=!DKl(jP&uR4!GZMM7uaNq}W?*A@K&4T` z^{gUgI30WhFz+0}MdlOtPOHDEC960NMI61-sz;#iKLE~z=IVlt->d4uHZ93EEp8&1bS?5Crf_C3QvE|L9PTn=7284CyNw9* znAmwQ*&jpSC(Hm2w*lKT_^U?CS3ttyK{tF8Up+)iIkc3}W)A%&bdbX%?f4uW zBi1Q@=fVT&$A^I8jJYlFXd?n6V*(>f<{CX;Z~U+}%;j2C+VT(0Nslenx>{d(SWnUC z2pQ3dVLdUAzvvNhem&?2UX^8Ao6YeeqK)> zSq`K=Pn#bFlWcCmjxA&}e{ag5^DMkWwiuinw?#^Nt#(UGUTsFbfv+tKy~K4|6{=^z54@t6vVQdnCo8n&QGoTT%pzx7&9co9m)j_3ImGvjHzZ6ABqtRA z?v|>x^JZiLhQ=Pfjt@Fmociys^y71=dv8nK){K2druAUmeSl;?xaX~a8pi}iX1rze zu)<7*bVGJIK&?E?H0P=ZL`z!`|VDp-EK8$b9;-3@ATH2U-5TtB+Hg?LE$j z!7-y29P*xCv2E`AMk;sMmT`z<^L4u0&R!E+^8tS|c*5H6Fvr@`NLC~cw{*&u@?k&~ z)+>WTZ*TCF`1_EnhUt$1Syqejii(Qy6SZj-eONW1xP*IS0}Q zuc6sbS~6O%7$5F?0u3GKOore}`qV&S>8CBJR?BBC5nHK@7(KHM{+DdR;C;sl15pp0 z2uQZYea@T5zTv|Hf!@ z?zaJ{)!*u=*7v^Uf;zpl9;aKf&?eF%XibS0qK*4bPi|NaW;K4x34Z-|Tv(&~ssZ5{ zodva|@AcgN=aBn*^c)i%!e*sSyNE=6LO9!!DoW4N!AdZ}>Q+*Zm-?NS5fl(935={Z zB8&(T@WJ|3kfpgp);KFiATJjKK&wRx6>AhWe407uqAj2WOR$Vc1py#%QwBv{|aaq@NYN=JL?`)wLpsI>S zoR?mM8U28Zzv>!~HX%l@QsUqEE%Co3Mz5YH58DKo##^}cN_UR6r7iUsDhd1>WLjeW zHdLv>J@~^wJyTCTQ!hvr(Nk|ws-`_Hv}_(YymN2P0PtCeSo8*YEx7AM$ zmhmYmD8TdmQz<$&p%?_Ea1MjZu5bn{dV>1OV!Dies;@;3B+ZcuGChpqYp%D@yT_32 zdcEwA^MU04I(m}QIZY!en&t0-y7IGTkY0_o$6!52uL|^8{0wWbe^}bmfhH_CX7dHT?VRU8#rj;u>oCY-HEeC>D-zZ~p zK`BO9F?#iqbk=qi{{3G=&T8})v2VzDZ9b6C5Zp5{xMj1J#?nV?rTZ3OimHWT`8*c! z^%H3`LhXEkLBPSca|vVA`DH|vtYS@?q}RoQIB0T9F5#byv!xh@?BjSGrNS!LF9L?doi%`sVcS|vG{BGL38JM}pVDqGVT0UC) z-NW!0$n9}2N5FSX?Z)XGG3LS(GxRUKV6YyTX+&5}D{d*GO?$v-q5?m-LqQJ)6dOE? zBSwYQ4{-$Tq7G{b|L$sFe%fq~DLU%PWW>N@k2yvefG1v=L-uE&6aJmkG==j1j-fnk zZa~*|&gD<$7@iBzFowm$5L{S-$Pf#SpojHL+%Yj_9@)2m9-I6v)o8Ey4gOAAKsm2y zUDXA&6q!WnBHE15I${aeU@VcB7zMEw2$JdgGCSxo38k)AJhe^7?5LF(O& z>@Y-`iD2$HYvCR)+LhXFL9gQ8(z7@0LQ&(lTsV(-i|ntW={4^L)c4A}sE^mJ@5>Z`M@A+&i4=Y;GwGtc@mN4hBR)Za zBiaD5WUZt|ju?!yuhAl{Pu7e7*0YRc z7qKq(J7J*pz1h--w|DUF=H?*xPioe`* zUtZcZwd%^+EF{?#S4>b#IKTH`|upjmzl+yK!JASA& z^Hae=i->PZ9M!cmv#vENY|~nX1e8(K4+;tq{oQw8Z39Wpx$m5F@45G!bI(05e=b~v zNz}Tan~Yh7U5Z5)UIO``%MTW{*QDwd=7qgi8WiGrS;=`LqM`xla?QD%cjR zyjR2j@;uJiR%W**Qo)m^cbokF1ePD~D^hkk^F{jGN3D(9!=sc&obfv}?Bl6Lit*}I zya4KE!{+1{6r+;Y>?USS%}N5wV<@KjJy_MNXuNsHi0^3R!l%?Cs?GdRiLO|Q zknVd;N}Hi&lvgWIV)!~fB0Lv@5-V7|N zm~;`i=+`CGM>6=$oiCwoHKIt6DwgRm_pMOMIulhbIC;3+lZVV#$mX@HP@+Ayt%OyG zDO#LDJ_q;MSE$4nV_2-8=w^f)g4H{ZdGDc zwu$&5<_`1S8@RV$X>(4jqE;u~e#FVHQACQdN1cgpaWBbQIHnjd<<}@qb;mITl}|4m z=j=^{4}~K&@ISUgvC+phNBRRy&Eo>hQser&}aW|b8&IT<`X~C6>-Vt+70ZFn@_7gVVo*Y?}R%{VLm!Jy8+`l*rl#v z??h&Ve@%kn4$y~PpebWSlqJGB|zc9YImT(vo4kLq86ef8e{u9C3xl=I;sq@ zUO_RZuR@z)I^|Ie*2n}G%UJ&Jws;!kJ$!zXf?V~OLO+i{e(wMUWGef!y-0 zteuC;xiDf{nO=IUO@^#6_NXEMtl9nXfGK7{x~9I zX20JU@8^w(JWvBL-%mzmjBBIvfch$FR6b~;#dw!{qH;gwtHf_c 一切自动 z(=127)、< chrome 置顶(999),故「内容→标题→slider值→chrome」。 + * 非控件直绘必须注册,否则 meow_ui_invalidate 清底后会漏画(非保留模型固有代价)。 */ +#define D_TITLE_Z 128 +static int g_dtitle_cid[D_TITLE_MAX]; /* 分区标题绘制物 id(rebuild 时注销/重注册) */ +static int g_slider_cid = 0; /* slider 值文本绘制物 id */ + +/* CUSTOM 绘制回调:分区标题(ctx=title 下标,指向 g_dtitle[i]) */ +static void demo_draw_title(void *ctx) +{ + int i = (int)(intptr_t)ctx; + if (i < 0 || i >= g_dtitle_n) return; + const meow_theme *th = meow_theme_get(); + meow_ui_text(g_dtitle[i].x, g_dtitle[i].y, g_dtitle[i].s, 20, th->primary); +} +/* CUSTOM 绘制回调:slider 当前值文本(bbox=r_slider_txt) */ +static void demo_draw_slider_val(void *ctx) +{ + (void)ctx; + if (!g_dslider) return; + const meow_theme *th = meow_theme_get(); + char buf[28]; snprintf(buf, sizeof buf, "slider = %d", meow_slider_get(g_dslider)); + meow_ui_text(r_slider_txt.x, r_slider_txt.y, buf, 20, th->dim); +} + /* 前向声明 */ static void redraw(void); static void demo_rebuild_to(int scroll); @@ -218,8 +243,16 @@ static void d_slot(meow_widget *w, rect_t r) } static void d_title(int x, int y, const char *s) { - if (g_dtitle_n < D_TITLE_MAX) { g_dtitle[g_dtitle_n].x = x; g_dtitle[g_dtitle_n].y = y; - g_dtitle[g_dtitle_n].s = s; g_dtitle_n++; } + if (g_dtitle_n < D_TITLE_MAX) { + int i = g_dtitle_n; + g_dtitle[i].x = x; g_dtitle[i].y = y; g_dtitle[i].s = s; + g_dtitle_n++; + /* 注册为 CUSTOM 绘制物(bbox=文本绘制范围;cb 读 g_dtitle[i]) */ + int tw = meow_ui_text_width(s, 20); + int th = meow_ui_text_height(20); + g_dtitle_cid[i] = meow_draw_custom_register(D_TITLE_Z, x, y, tw, th, + demo_draw_title, (void *)(intptr_t)i); + } } /* LazyColumn 数据源(100 项虚拟化) */ @@ -231,12 +264,15 @@ static int demo_list_src(int idx, char *label, int len, void *ctx) return 1; } -/* 释放当前全部内容控件(含 Card 的独立子按钮);chrome 不在其列。 */ +/* 释放当前全部内容控件(含 Card 的独立子按钮)与 CUSTOM 绘制物;chrome 不在其列。 */ static void demo_free_content(void) { for (int i = 0; i < g_dslot_n; i++) meow_widget_free(g_dslot[i].w); g_dslot_n = 0; if (g_dcard_btn) { meow_widget_free(g_dcard_btn); g_dcard_btn = NULL; } + for (int i = 0; i < g_dtitle_n; i++) + if (g_dtitle_cid[i] > 0) { meow_draw_unregister(g_dtitle_cid[i]); g_dtitle_cid[i] = 0; } + if (g_slider_cid > 0) { meow_draw_unregister(g_slider_cid); g_slider_cid = 0; } g_dtitle_n = 0; } @@ -272,8 +308,11 @@ static void demo_build_at(int scroll) d_title(DCL_X, SY(yb), "INPUT & STATE"); yb += 26; r_dsw = RX(DCL_X, SY(yb), 56, 32); g_dsw = meow_switch_create(r_dsw.x, r_dsw.y, g_ds.sw_on); SLOT(g_dsw, r_dsw.x, r_dsw.y, r_dsw.w, r_dsw.h); yb += 44; - r_slider_txt = RX(DCL_X, SY(yb), 100, 24); yb += 24; + r_slider_txt = RX(DCL_X, SY(yb), 160, 24); yb += 24; /* 加宽到覆盖值文本全宽(防局部刷漏尾) */ r_slider = RX(DCL_X, SY(yb), DFW, 40); g_dslider = meow_slider_create(r_slider.x, r_slider.y, r_slider.w, 0, 100, g_ds.slider); SLOT(g_dslider, r_slider.x, r_slider.y, r_slider.w, r_slider.h); yb += 48; + g_slider_cid = meow_draw_custom_register(D_TITLE_Z, r_slider_txt.x, r_slider_txt.y, + r_slider_txt.w, r_slider_txt.h, + demo_draw_slider_val, NULL); r_dtf = RX(DCL_X, SY(yb), DFW, 44); g_dtf = meow_textfield_create(r_dtf.x, r_dtf.y, r_dtf.w, r_dtf.h, "Type here...", g_ds.tf, 32, MEOW_IME_ASCII); SLOT(g_dtf, r_dtf.x, r_dtf.y, r_dtf.w, r_dtf.h); yb += 54; @@ -332,27 +371,14 @@ static void demo_build_at(int scroll) #undef SLOT } -/* demo 全页重绘:背景 + 内容控件(已定位) + 标题 + slider 值 + chrome(后画覆盖) + 内容区 flush */ +/* demo 全页重绘:整帧按 z 序重画全部(set_page_bg 清底 + 注册表按 z 升序)。 + * 此前手工遍历 g_dslot/g_dtitle/后画 chrome 已删;现在自动 z 排:内容(0..127)→标题/slider值(128) + * →chrome(999 置顶),与旧绘制序一致,但「清底+重画」由 SDK 统一按 z 保证(P1 修法下沉)。 */ static void demo_paint(void) { const meow_theme *th = meow_theme_get(); - int sb = meow_ui_statusbar_height(); - - meow_ui_fill_rect(0, sb, 480, 720 - sb, th->bg); - - for (int i = 0; i < g_dslot_n; i++) meow_widget_draw(g_dslot[i].w); - for (int i = 0; i < g_dtitle_n; i++) - meow_ui_text(g_dtitle[i].x, g_dtitle[i].y, g_dtitle[i].s, 20, th->primary); - if (g_dslider) { - char buf[28]; snprintf(buf, sizeof buf, "slider = %d", meow_slider_get(g_dslider)); - meow_ui_text(r_slider_txt.x, r_slider_txt.y, buf, 20, th->dim); - } - /* chrome(固定;后画覆盖内容溢出区) */ - meow_widget_draw(g_tb); - meow_widget_draw(g_nav); - meow_widget_draw(g_fab); - - meow_ui_flush_region(0, sb, 480, 720 - sb); + meow_ui_set_page_bg(th->bg); /* 页面底 = 主题 bg(区域/整帧重画清底用) */ + meow_ui_paint_full(); /* 整帧按 z 序重画 */ } /* 重建内容到指定 scroll(clamp 到 [0, max_scroll]);进入/滚动共用 */ @@ -369,51 +395,14 @@ static void demo_rebuild_to(int scroll) demo_paint(); } -/* 两矩形是否相交(P1:局部重绘时判定哪些控件落在该区) */ -static int d_rect_overlap(rect_t a, rect_t b) -{ - return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y; -} - -/* 局部刷新一个区域:清底 + 按 demo_paint 同序重画「落在该区的所有控件/文本/chrome」,再 flush。 - * 根治 P1:旧 d_redraw 只清底 + 重画单个控件,会把重叠区里上层控件(chrome 如 FAB/导航栏) - * 一并清掉、只刷单个控件矩形 → 下层动态控件(如圆形进度条实时重绘)盖住/抹掉上层浮层。 - * 修法:局部刷新=重画该区内完整 z 栈(内容→标题→slider 值→chrome,与整帧 paint 一致), - * 下层动态重绘不再抹掉上层。仍是局部(只画相交控件,不整帧、不冲状态栏)。 */ -static void d_paint_region(rect_t r) -{ - if (r.w <= 0 || r.h <= 0) return; - const meow_theme *th = meow_theme_get(); - meow_ui_fill_rect(r.x, r.y, r.w, r.h, th->bg); - for (int i = 0; i < g_dslot_n; i++) - if (d_rect_overlap(g_dslot[i].r, r)) meow_widget_draw(g_dslot[i].w); - for (int i = 0; i < g_dtitle_n; i++) - if (g_dtitle[i].y < r.y + r.h && g_dtitle[i].y + meow_ui_text_height(20) > r.y && - g_dtitle[i].x < r.x + r.w && g_dtitle[i].x + meow_ui_text_width(g_dtitle[i].s, 20) > r.x) - meow_ui_text(g_dtitle[i].x, g_dtitle[i].y, g_dtitle[i].s, 20, th->primary); - if (g_dslider && d_rect_overlap(r_slider_txt, r)) { - char buf[28]; snprintf(buf, sizeof buf, "slider = %d", meow_slider_get(g_dslider)); - meow_ui_text(r_slider_txt.x, r_slider_txt.y, buf, 20, th->dim); - } - /* chrome(固定;后画保证覆盖内容区溢出) */ - if (d_rect_overlap(r_tb, r)) meow_widget_draw(g_tb); - if (d_rect_overlap(r_nav, r)) meow_widget_draw(g_nav); - if (d_rect_overlap(r_fab, r)) meow_widget_draw(g_fab); - meow_ui_flush_region(r.x, r.y, r.w, r.h); -} - -/* 局部刷新一个控件:整区清底 + 重画重叠 z 栈(w 仅用于取矩形;重画逻辑见 d_paint_region) */ -static void d_redraw(meow_widget *w, rect_t r) -{ - (void)w; - d_paint_region(r); -} - +/* 局部刷新统一走 SDK meow_ui_invalidate(清底 + 按 z 重画相交绘制物 + 上屏); + * 旧 d_paint_region/d_redraw/d_rect_overlap(App 层 z 栈重画)已删除、下沉到 SDK(§6.2)。 + * 局部刷新一控件:整区清底 + 重画重叠 z 栈由注册表完成。 */ static void d_toggle_sel(meow_widget *w, rect_t r) { if (!w) return; meow_widget_set_selected(w, !meow_widget_selected(w)); - d_redraw(w, r); + meow_ui_invalidate(r.x, r.y, r.w, r.h); } /* Tap:落点在内容控件上,返回 1=已消费 */ @@ -423,29 +412,29 @@ static int demo_content_tap(int x, int y) for (int i = 0; i < 5; i++) if (meow_widget_hit(g_dbtn_b[i], x, y)) { d_toggle_sel(g_dbtn_b[i], r_btn[i]); g_ds.btn[i] = meow_widget_selected(g_dbtn_b[i]); return 1; } - if (meow_widget_hit(g_dr1, x, y)) { meow_widget_set_selected(g_dr1, 1); meow_widget_set_selected(g_dr2, 0); g_ds.r1 = 1; g_ds.r2 = 0; d_redraw(g_dr1, r_dr1); d_redraw(g_dr2, r_dr2); return 1; } - if (meow_widget_hit(g_dr2, x, y)) { meow_widget_set_selected(g_dr2, 1); meow_widget_set_selected(g_dr1, 0); g_ds.r2 = 1; g_ds.r1 = 0; d_redraw(g_dr1, r_dr1); d_redraw(g_dr2, r_dr2); return 1; } + if (meow_widget_hit(g_dr1, x, y)) { meow_widget_set_selected(g_dr1, 1); meow_widget_set_selected(g_dr2, 0); g_ds.r1 = 1; g_ds.r2 = 0; meow_ui_invalidate(r_dr1.x, r_dr1.y, r_dr1.w, r_dr1.h); meow_ui_invalidate(r_dr2.x, r_dr2.y, r_dr2.w, r_dr2.h); return 1; } + if (meow_widget_hit(g_dr2, x, y)) { meow_widget_set_selected(g_dr2, 1); meow_widget_set_selected(g_dr1, 0); g_ds.r2 = 1; g_ds.r1 = 0; meow_ui_invalidate(r_dr1.x, r_dr1.y, r_dr1.w, r_dr1.h); meow_ui_invalidate(r_dr2.x, r_dr2.y, r_dr2.w, r_dr2.h); return 1; } if (meow_widget_hit(g_dcb, x, y)) { d_toggle_sel(g_dcb, r_dcb); g_ds.ck = meow_widget_selected(g_dcb); return 1; } - if (meow_widget_hit(g_dsw, x, y)) { g_ds.sw_on = !meow_switch_get(g_dsw); meow_switch_set(g_dsw, g_ds.sw_on); d_redraw(g_dsw, r_dsw); return 1; } + if (meow_widget_hit(g_dsw, x, y)) { g_ds.sw_on = !meow_switch_get(g_dsw); meow_switch_set(g_dsw, g_ds.sw_on); meow_ui_invalidate(r_dsw.x, r_dsw.y, r_dsw.w, r_dsw.h); return 1; } if (meow_widget_hit(g_dslider, x, y)) { demo_slider_drag(x); return 1; } if (meow_widget_hit(g_dtf, x, y)) { meow_textfield_activate(g_dtf); /* 阻塞 IME,返回后刷新 + 状态回写 */ strncpy(g_ds.tf, meow_textfield_text(g_dtf), sizeof g_ds.tf - 1); g_ds.tf[sizeof g_ds.tf - 1] = 0; - d_redraw(g_dtf, r_dtf); + meow_ui_invalidate(r_dtf.x, r_dtf.y, r_dtf.w, r_dtf.h); return 1; } if (meow_widget_hit(g_dcard_btn, x, y)) { d_toggle_sel(g_dcard_btn, r_cardbtn); g_ds.card = meow_widget_selected(g_dcard_btn); return 1; } if (g_dtab) { int t = meow_tabbar_hit(g_dtab, x, y); - if (t >= 0) { g_ds.tab = t; meow_tabbar_set_selected(g_dtab, t); d_redraw(g_dtab, r_tab); return 1; } + if (t >= 0) { g_ds.tab = t; meow_tabbar_set_selected(g_dtab, t); meow_ui_invalidate(r_tab.x, r_tab.y, r_tab.w, r_tab.h); return 1; } } - if (meow_widget_hit(g_dbtn_dlg, x, y)) { meow_dialog_show(g_dlg); meow_log(MEOW_LOG_INFO, "dialog result=%d", meow_dialog_result(g_dlg)); d_redraw(g_dbtn_dlg, r_dlg); return 1; } - if (meow_widget_hit(g_dbtn_sheet, x, y)) { int r = meow_sheet_open(g_sheet); meow_log(MEOW_LOG_INFO, "sheet result=%d", r); d_redraw(g_dbtn_sheet, r_sheet); return 1; } + if (meow_widget_hit(g_dbtn_dlg, x, y)) { meow_dialog_show(g_dlg); meow_log(MEOW_LOG_INFO, "dialog result=%d", meow_dialog_result(g_dlg)); meow_ui_invalidate(r_dlg.x, r_dlg.y, r_dlg.w, r_dlg.h); return 1; } + if (meow_widget_hit(g_dbtn_sheet, x, y)) { int r = meow_sheet_open(g_sheet); meow_log(MEOW_LOG_INFO, "sheet result=%d", r); meow_ui_invalidate(r_sheet.x, r_sheet.y, r_sheet.w, r_sheet.h); return 1; } if (meow_widget_hit(g_dlc, x, y)) { g_demo_focus = 1; int li = meow_list_tap_at(g_dlc, x, y); /* M2.71-bug8:命中行→置选中并高亮 */ - if (li >= 0) { g_ds.list_sel = li; d_redraw(g_dlc, r_list); } + if (li >= 0) { g_ds.list_sel = li; meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); } return 1; } return 0; @@ -463,12 +452,13 @@ static void demo_on_tap(int x, int y) char lb[16]; snprintf(lb, sizeof lb, "+%d", g_demo_fab); meow_widget_free(g_fab); g_fab = meow_fab_create(r_fab.x, r_fab.y, 56, lb); - d_paint_region(r_fab); /* 重画 FAB 及其下重叠内容(z 序一致,防抹掉下层) */ + meow_widget_set_z(g_fab, 999); /* 重建后重挂顶:新 entry 自动 z 低,须显式置顶 */ + meow_ui_invalidate(r_fab.x, r_fab.y, r_fab.w, r_fab.h); /* 重画 FAB 及其下重叠 z 栈 */ return; } if (g_nav) { int idx = meow_navigationbar_hit(g_nav, x, y); - if (idx >= 0) { meow_navigationbar_set_selected(g_nav, idx); d_redraw(g_nav, r_nav); return; } + if (idx >= 0) { meow_navigationbar_set_selected(g_nav, idx); meow_ui_invalidate(r_nav.x, r_nav.y, r_nav.w, r_nav.h); return; } } if (demo_content_tap(x, y)) return; } @@ -481,8 +471,8 @@ static void demo_tick(uint64_t now) g_demo_prog_last = now; g_ds.prog = (g_ds.prog + 3) % 101; g_demo_prog = g_ds.prog; - meow_progress_set(g_dprl, g_demo_prog); d_redraw(g_dprl, r_prl); - meow_progress_set(g_dprc, g_demo_prog); d_redraw(g_dprc, r_prc); + meow_progress_set(g_dprl, g_demo_prog); meow_ui_invalidate(r_prl.x, r_prl.y, r_prl.w, r_prl.h); + meow_progress_set(g_dprc, g_demo_prog); meow_ui_invalidate(r_prc.x, r_prc.y, r_prc.w, r_prc.h); } /* 按触碰 X 落 slider 值并局部刷(按下即定位 + 拖动实时,M2.71-bug2) */ @@ -491,8 +481,8 @@ static void demo_slider_drag(int x) int frac = x - r_slider.x; if (frac < 0) frac = 0; if (frac > r_slider.w) frac = r_slider.w; g_ds.slider = frac * 100 / r_slider.w; meow_slider_set(g_dslider, g_ds.slider); - d_redraw(g_dslider, r_slider); - d_paint_region(r_slider_txt); /* 重画 slider 值文本(z 序一致) */ + meow_ui_invalidate(r_slider.x, r_slider.y, r_slider.w, r_slider.h); + meow_ui_invalidate(r_slider_txt.x, r_slider_txt.y, r_slider_txt.w, r_slider_txt.h); /* 重画值文本 */ } /* demo 页 on_touch_down:锁一种拖拽(slider > list > 页内容)。非 demo 态跳过。 @@ -522,7 +512,7 @@ static void demo_touch_move(int x, int y) if (g_drag_slider) { demo_slider_drag(x); return; } if (g_drag_list) { int dy = y - g_drag_list_last_y; g_drag_list_last_y = y; - if (dy) { meow_list_scroll_by(g_dlc, -dy); g_ds.list = meow_list_scroll(g_dlc); d_redraw(g_dlc, r_list); } + if (dy) { meow_list_scroll_by(g_dlc, -dy); g_ds.list = meow_list_scroll(g_dlc); meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); } return; } if (g_drag_page) { @@ -546,7 +536,7 @@ static void demo_swipe(int dir, int dist) if (g_demo_focus && g_dlc) { meow_list_scroll_by(g_dlc, del); g_ds.list = meow_list_scroll(g_dlc); - d_redraw(g_dlc, r_list); /* 列表区局部刷新 */ + meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); /* 列表区局部刷新 */ } else { demo_rebuild_to(g_demo_scroll + del); } @@ -575,6 +565,10 @@ static void demo_init(void) meow_navigationbar_add_item(g_nav, "More"); meow_navigationbar_set_selected(g_nav, 0); r_fab = RX(406, 616, 56, 56); g_fab = meow_fab_create(406, 616, 56, "+"); + /* chrome 显式置顶(§6.2 置顶):> 一切自动 z(127),区域重画/整帧都最后画 chrome。 */ + meow_widget_set_z(g_tb, 999); + meow_widget_set_z(g_nav, 999); + meow_widget_set_z(g_fab, 999); demo_build_at(0); meow_ui_activity_pop(); g_demo_scroll = 0; diff --git a/patch_v2/sdk/build_sdk.sh b/patch_v2/sdk/build_sdk.sh index 9994d4d..b7440e4 100755 --- a/patch_v2/sdk/build_sdk.sh +++ b/patch_v2/sdk/build_sdk.sh @@ -10,7 +10,7 @@ AR="${AR:-/usr/bin/ar}" # 系统 GNU ar 即可归档 mipsel ELF 对象(架 rm -f meow_ui.a *.o # -I../meow_launcherd:meow_notify_ipc.c 复用共享协议头 meow_ipc.h(同一份、杜绝两端漂移) -OBJS="meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config stb_image" +OBJS="meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config meow_ui_draw meow_ui_view stb_image" CFLAGS="-Os -static -I$ROOT/patch_v2/meow_launcherd" for f in $OBJS; do echo "== cc $f ==" diff --git a/patch_v2/sdk/meow_ui.h b/patch_v2/sdk/meow_ui.h index 4c3da44..c1df222 100644 --- a/patch_v2/sdk/meow_ui.h +++ b/patch_v2/sdk/meow_ui.h @@ -210,6 +210,58 @@ void meow_ui_global_remove(int id); /* ③ 系统级控件:状态栏/通知中心/左缘返回滑条/电源菜单等全局叠加层——仅 SDK 内部接口, * 不向用户 App 开放任何公共悬浮/叠加层 API。既有状态栏/返回滑条逻辑(§3.1)不动。 */ +/* ============================================================ */ +/* §6.2 绘制物注册表 / z 序 / 区域重画(合并 SDK_Z_ORDER_DESIGN,源:2026-08-31) + * ------------------------------------------------------------ + * 非保留模型(§5.8.7)下,把「清底 + 按 z 重画重叠区完整 z 栈」下沉到 SDK,让所有 App + * 自动获得正确的局部重画(根治 P1:下层动态控件局部重绘会把重叠区上层 chrome 抹掉)。 + * - 控件(meow_widget)创建即自动注册进绘制物注册表;rect 实时读 w->x/y/w/h; + * - App 直绘的非控件内容(meow_ui_text/fill_rect 等)须显式 meow_draw_custom_register + * 注册(声明 bbox + 绘制回调),否则区域重画会漏画(非保留模型固有代价); + * - z 自动推导(子>父、同层注册先序);显式 meow_widget_set_z(999/MEOW_Z_TOP) 置顶(粘滞)。 + * 用法:meow_ui_invalidate(x,y,w,h) 局部重画(清底+按 z 升序重画所有相交绘制物+上屏), + * 不整帧;meow_ui_paint_full() 整帧按 z 序重画。默认底=meow_theme bg(set_page_bg 覆盖)。 + * 兼容:新 API 全部 opt-in;不调用本节的既有 App(widget/activity/flush 均不动)行为完全不变。 */ +/* ============================================================ */ + +/* 绘制物种类:控件(自动注册)/ App 直绘内容(显式注册)。 */ +typedef enum { MEOW_ITEM_WIDGET = 0, MEOW_ITEM_CUSTOM = 1 } meow_draw_kind; +typedef void (*meow_draw_fn)(void *ctx); /* CUSTOM 绘制回调(ctx 由 App 持有) */ + +/* ---- 层级常量(保证"子>父" + 值域远小于置顶值)---- */ +#define MEOW_Z_STRIDE 16 /* 每层容器嵌套的 z 步进(子层至少 +16) */ +#define MEOW_Z_DEPTH_MAX 7 /* 自动推导最大嵌套深度(0..6,>7 折叠) */ +#define MEOW_Z_PER_LEVEL_MAX 15 /* 每层最多 16 槽(seq 0..15,超出折叠按注册序) */ +#define MEOW_Z_AUTO_MAX (MEOW_Z_STRIDE * MEOW_Z_DEPTH_MAX + MEOW_Z_PER_LEVEL_MAX) /* 127 */ +#define MEOW_Z_TOP 1000 /* 惯例"置顶"值;≥(MEOW_Z_AUTO_MAX+1)=128 即超一切自动值 */ + +/* 控件显式置层:z 为任意非负整数(0..INT_MAX,无上限),越大越上;z>所有其它控件即恒在最上。 + * 惯例设 999(或 MEOW_Z_TOP)即"置顶"。显式 z 存于绘制注册表(按 w 反查 entry,不改 + * struct meow_widget——零 ABI 破坏)且**粘滞**:不被后续自动推导覆盖;clear_z 才回退。 */ +void meow_widget_set_z(meow_widget *w, int z); +int meow_widget_z(const meow_widget *w); /* 当前生效 z(显式=其值,否则=自动推导) */ +void meow_widget_clear_z(meow_widget *w); /* 清除显式 z,回退自动推导 */ + +/* ---- 非控件直绘内容注册为绘制物(CUSTOM)---- + * App 声明 bbox + 绘制回调 + 显式 z(任意非负;999=置顶);区域重画/整帧重画会画到它。 + * 返回 id(供 meow_draw_unregister / meow_draw_set_z);注册表满返回 0。 + * 生命周期契约:App 持有 ctx;widget 类内容不必注册(自动);离开页面前 unregister。 */ +int meow_draw_custom_register(int z, int x, int y, int w, int h, + meow_draw_fn cb, void *ctx); +void meow_draw_unregister(int id); /* 注销(id 失效,勿再用) */ +int meow_draw_set_z(int id, int z); /* 改 custom 显式 z;无效 id 返回 -1 */ + +/* 页面背景色(区域重画/整帧清底用);默认 meow_theme bg。 */ +void meow_ui_set_page_bg(uint32_t color); +uint32_t meow_ui_page_bg(void); + +/* 声明某区域内容已变化 → 清底(page_bg) + 按 z 升序重画所有相交绘制物 + 上屏。 + * 局部(只画相交绘制物,完整 bbox——见 SDK_Z_ORDER_DESIGN §5),不整帧、不冲状态栏。 */ +void meow_ui_invalidate(int x, int y, int w, int h); + +/* 整帧按 z 序重画全部(set_page_bg 清底 + 全注册表按 z 升序 + 上屏)。 */ +void meow_ui_paint_full(void); + /* ============================================================ */ /* §3.1 全局状态栏 / 全屏(A-0,SDK 系统级组件) */ /* ============================================================ */ diff --git a/patch_v2/sdk/meow_ui_draw.c b/patch_v2/sdk/meow_ui_draw.c new file mode 100644 index 0000000..fc25145 --- /dev/null +++ b/patch_v2/sdk/meow_ui_draw.c @@ -0,0 +1,357 @@ +/* + * meow_ui_draw.c — 绘制物注册表 / z 序 / 区域重画(§6.2 / SDK_Z_ORDER_DESIGN §2)。 + * + * 非保留模型下,把「清底 + 按 z 重画重叠区完整 z 栈」下沉到 SDK: + * - 控件(meow_widget)创建即自动注册(create 末尾调 meow_draw_widget_register), + * meow_widget_free 自动注销;rect 实时读 w->x/y/w/h; + * - App 直绘的非控件内容显式 meow_draw_custom_register(声明 bbox + 绘制回调); + * - z 自动推导(子>父、同层注册先序);显式 set_z 粘滞、置顶。 + * 显式 z 存于本注册表(按 w 反查 entry),**不改 struct meow_widget**(零 ABI 破坏)。 + */ +#include "meow_ui.h" +#include "meow_ui_internal.h" +#include "meow_ui_view.h" +#include +#include + +#define MEOW_DRAW_MAX 256 +#define MEOW_ITEM_VIEW 2 /* 内部 kinds(不进公共枚举):meow_view 绘制物 */ + +typedef struct draw_entry { + int kind; /* MEOW_ITEM_WIDGET / MEOW_ITEM_CUSTOM / MEOW_ITEM_VIEW */ + meow_widget *w; /* WIDGET:绘制其 meow_widget_draw(w) */ + meow_draw_fn draw_cb; /* CUSTOM:绘制回调 */ + void *ctx; /* CUSTOM: 传给 draw_cb; VIEW: (meow_view*)v */ + int rx, ry, rw, rh; /* CUSTOM bbox(WIDGET 读 w->x/y/w/h,VIEW 读 v->x/y/w/h) */ + int z; /* 生效 z(显式=其值,否则=自动推导) */ + int z_explicit; /* 1=显式(粘滞) */ + int id; /* CUSTOM id(0=无效) */ + int seq; /* 全局注册序(z 同值时稳定先序) */ + struct meow_view *view; /* WIDGET:所属 view(z 深度源)+1 */ +} draw_entry; + +static draw_entry g_e[MEOW_DRAW_MAX]; +static int g_n = 0; +static int g_seq = 0; /* 全局注册序(单调递增) */ +static int g_next_id = 1; /* CUSTOM id 起点(0=无效) */ + +static uint32_t g_page_bg = 0; +static int g_page_bg_set = 0; + +/* ---- 内部访问器(widget.c 提供;跨 TU 用 meow_ui_internal.h 声明)---- */ +static int w_is_layout(const meow_widget *w) { return meow_widget_is_layout(w); } + +/* ---- 查找 ---- */ +static draw_entry *e_find_widget(const meow_widget *w) +{ + for (int i = 0; i < g_n; i++) + if (g_e[i].kind == MEOW_ITEM_WIDGET && g_e[i].w == w) return &g_e[i]; + return NULL; +} +static draw_entry *e_find_view(const meow_view *v) +{ + for (int i = 0; i < g_n; i++) + if (g_e[i].kind == MEOW_ITEM_VIEW && g_e[i].ctx == (void *)v) return &g_e[i]; + return NULL; +} +static draw_entry *e_find_id(int id) +{ + for (int i = 0; i < g_n; i++) + if (g_e[i].kind == MEOW_ITEM_CUSTOM && g_e[i].id == id) return &g_e[i]; + return NULL; +} + +/* ---- 深度:view 树深度 ---- */ +static int view_depth(const meow_view *v) +{ + int d = 0; + const meow_view *p = v ? v->parent : NULL; + while (p) { + d++; + if (d > MEOW_Z_DEPTH_MAX) break; + p = p->parent; + } + return d; +} + +/* ---- 深度:widget 所属嵌套深度(view 树为主;否则 W_LAYOUT children 反推;否则 0)---- */ +static int widget_nest_depth(meow_widget *w, int depth) +{ + if (depth > MEOW_Z_DEPTH_MAX) return MEOW_Z_DEPTH_MAX; + draw_entry *e = e_find_widget(w); + if (e && e->view) return view_depth(e->view) + 1; /* 视图树深度源(更确定) */ + /* 注册表反推:w 是否经 meow_layout_add 挂在某布局下(此时布局自身已注册为 WIDGET)。 */ + for (int i = 0; i < g_n; i++) { + if (g_e[i].kind != MEOW_ITEM_WIDGET) continue; + meow_widget *lw = g_e[i].w; + if (!lw || !w_is_layout(lw)) continue; + int nc = meow_widget_nchild(lw); + for (int j = 0; j < nc; j++) + if (meow_widget_child_at(lw, j) == w) + return widget_nest_depth(lw, depth + 1) + 1; /* 子层 >= 父层+1 */ + } + return 0; +} + +/* 计算 auto z(显式不重算——粘滞):depth*STRIDE + 层内 seq(注册先序,折叠 MEOW_Z_PER_LEVEL_MAX)。 */ +static void e_compute_auto(draw_entry *e) +{ + if (e->z_explicit) return; + int depth = 0; + if (e->kind == MEOW_ITEM_WIDGET && e->w) depth = widget_nest_depth(e->w, 0); + else if (e->kind == MEOW_ITEM_VIEW && e->ctx) depth = view_depth((const meow_view *)e->ctx); + /* CUSTOM:z 恒显式(register 传入),不进 auto 分支 */ + int cnt = 0; + for (int i = 0; i < g_n; i++) { + draw_entry *o = &g_e[i]; + if (o == e || o->z_explicit) continue; + if (o->seq >= e->seq) continue; + if (o->z / MEOW_Z_STRIDE == depth) cnt++; + } + if (cnt > MEOW_Z_PER_LEVEL_MAX) cnt = MEOW_Z_PER_LEVEL_MAX; + e->z = depth * MEOW_Z_STRIDE + cnt; +} + +/* ============================================================ */ +/* 控件自动注册 / 注销(create 末尾 / meow_widget_free 调用) */ +/* ============================================================ */ +void meow_draw_widget_register(meow_widget *w) +{ + if (!w || e_find_widget(w)) return; /* 幂等 */ + if (g_n >= MEOW_DRAW_MAX) return; /* 满:静默(骨架级) */ + draw_entry *e = &g_e[g_n++]; + memset(e, 0, sizeof *e); + e->kind = MEOW_ITEM_WIDGET; + e->w = w; + e->seq = g_seq++; + e_compute_auto(e); +} + +void meow_draw_widget_unregister(meow_widget *w) +{ + if (!w) return; + int idx = -1; + for (int i = 0; i < g_n; i++) + if (g_e[i].kind == MEOW_ITEM_WIDGET && g_e[i].w == w) { idx = i; break; } + if (idx < 0) return; + g_e[idx] = g_e[--g_n]; /* 交换移除(seq 保留,排序稳定) */ +} + +int meow_draw_widget_registered(const meow_widget *w) +{ + return w ? e_find_widget(w) != NULL : 0; +} + +void meow_draw_widget_set_view(meow_widget *w, struct meow_view *v) +{ + draw_entry *e = e_find_widget(w); + if (!e) return; + e->view = v; + e_compute_auto(e); +} + +/* ============================================================ */ +/* 显式 z(widget) */ +/* ============================================================ */ +void meow_widget_set_z(meow_widget *w, int z) +{ + if (!w || z < 0) return; + draw_entry *e = e_find_widget(w); + if (!e) return; + e->z_explicit = 1; + e->z = z; +} +int meow_widget_z(const meow_widget *w) +{ + if (!w) return 0; + draw_entry *e = e_find_widget((meow_widget *)w); + if (!e) return 0; + if (e->z_explicit) return e->z; + e_compute_auto(e); + return e->z; +} +void meow_widget_clear_z(meow_widget *w) +{ + if (!w) return; + draw_entry *e = e_find_widget(w); + if (!e) return; + e->z_explicit = 0; + e_compute_auto(e); +} + +/* ============================================================ */ +/* CUSTOM(App 直绘)注册 / 注销 / 改 z */ +/* ============================================================ */ +int meow_draw_custom_register(int z, int x, int y, int w, int h, + meow_draw_fn cb, void *ctx) +{ + if (!cb || w <= 0 || h <= 0) return 0; + if (g_n >= MEOW_DRAW_MAX) return 0; + draw_entry *e = &g_e[g_n++]; + memset(e, 0, sizeof *e); + e->kind = MEOW_ITEM_CUSTOM; + e->draw_cb = cb; + e->ctx = ctx; + e->rx = x; e->ry = y; e->rw = w; e->rh = h; + e->z = z < 0 ? 0 : z; + e->z_explicit = 1; + e->id = g_next_id++; + e->seq = g_seq++; + return e->id; +} +void meow_draw_unregister(int id) +{ + if (id <= 0) return; + int idx = -1; + for (int i = 0; i < g_n; i++) + if (g_e[i].kind == MEOW_ITEM_CUSTOM && g_e[i].id == id) { idx = i; break; } + if (idx < 0) return; + g_e[idx] = g_e[--g_n]; +} +int meow_draw_set_z(int id, int z) +{ + if (id <= 0 || z < 0) return -1; + draw_entry *e = e_find_id(id); + if (!e) return -1; + e->z = z; + e->z_explicit = 1; + return 0; +} + +/* ============================================================ */ +/* view 绘制物注册 / 注销 */ +/* ============================================================ */ +void meow_draw_view_register(struct meow_view *v) +{ + if (!v || e_find_view(v)) return; + if (g_n >= MEOW_DRAW_MAX) return; + draw_entry *e = &g_e[g_n++]; + memset(e, 0, sizeof *e); + e->kind = MEOW_ITEM_VIEW; + e->ctx = (void *)v; + e->seq = g_seq++; + e_compute_auto(e); +} +void meow_draw_view_unregister(struct meow_view *v) +{ + if (!v) return; + int idx = -1; + for (int i = 0; i < g_n; i++) + if (g_e[i].kind == MEOW_ITEM_VIEW && g_e[i].ctx == (void *)v) { idx = i; break; } + if (idx < 0) return; + g_e[idx] = g_e[--g_n]; +} +int meow_draw_view_entered(const struct meow_view *v) +{ + return v ? meow_view_get_state(v) & MEOW_VIEW_STATE_ENTERED : 0; +} +void meow_draw_view_set_z(struct meow_view *v, int z) +{ + draw_entry *e = e_find_view(v); + if (!e) return; + if (z <= 0) { + e->z_explicit = 0; + e_compute_auto(e); + } else { + e->z_explicit = 1; + e->z = z; + } +} + +/* ============================================================ */ +/* page bg / 区域重画 / 整帧 */ +/* ============================================================ */ +void meow_ui_set_page_bg(uint32_t color) { g_page_bg = color; g_page_bg_set = 1; } +uint32_t meow_ui_page_bg(void) { return g_page_bg_set ? g_page_bg : meow_theme_get()->bg; } + +static int rect_hit(int ax, int ay, int aw, int ah, int bx, int by, int bw, int bh) +{ + return ax < bx + bw && ax + aw > bx && ay < by + bh && ay + ah > by; +} + +static int entry_rect(draw_entry *e, int out[4]) +{ + if (e->kind == MEOW_ITEM_WIDGET && e->w) { + meow_widget_rect(e->w, out); + } else if (e->kind == MEOW_ITEM_VIEW && e->ctx) { + meow_view *v = (meow_view *)e->ctx; + out[0] = v->x; out[1] = v->y; out[2] = v->w; out[3] = v->h; + } else { + out[0] = e->rx; out[1] = e->ry; out[2] = e->rw; out[3] = e->rh; + } + return out[2] > 0 && out[3] > 0; +} + +static void draw_one(draw_entry *e) +{ + switch (e->kind) { + case MEOW_ITEM_WIDGET: + meow_widget_draw(e->w); + break; + case MEOW_ITEM_CUSTOM: + e->draw_cb(e->ctx); + break; + case MEOW_ITEM_VIEW: { + meow_view *v = (meow_view *)e->ctx; + if (v->hooks.on_draw) v->hooks.on_draw(v, meow_theme_get(), v->ctx); + break; + } + default: + break; + } +} + +static void paint(int full, int x, int y, int w, int h) +{ + uint32_t bg = meow_ui_page_bg(); + if (full) { + meow_ui_clear(bg); + } else { + if (w <= 0 || h <= 0) return; + meow_ui_fill_rect(x, y, w, h, bg); + } + /* 刷新 auto z + 组装按 (z,seq) 升序的绘制序(owner==active 过滤 WIDGET;view 须已进入)。 */ + draw_entry *order[MEOW_DRAW_MAX]; + int nn = 0; + int active = meow_ui_activity_active(); + for (int i = 0; i < g_n; i++) { + draw_entry *e = &g_e[i]; + e_compute_auto(e); + if (e->kind == MEOW_ITEM_WIDGET && e->w && meow_widget_owner(e->w) != active) continue; + if (e->kind == MEOW_ITEM_VIEW && !meow_draw_view_entered((meow_view *)e->ctx)) continue; + order[nn++] = e; + } + /* 稳定插入排序:(z 升序,同 z 按 seq 升序=注册先序)。 */ + for (int i = 1; i < nn; i++) { + draw_entry *key = order[i]; + int j = i - 1; + while (j >= 0 && (order[j]->z > key->z || + (order[j]->z == key->z && order[j]->seq > key->seq))) { + order[j + 1] = order[j]; + j--; + } + order[j + 1] = key; + } + if (full) { + for (int i = 0; i < nn; i++) draw_one(order[i]); + meow_ui_flush(); + } else { + int r[4]; + for (int i = 0; i < nn; i++) { + if (!entry_rect(order[i], r)) continue; + if (rect_hit(r[0], r[1], r[2], r[3], x, y, w, h)) draw_one(order[i]); + } + meow_ui_flush_region(x, y, w, h); + } +} + +void meow_ui_invalidate(int x, int y, int w, int h) +{ + if (w <= 0 || h <= 0) return; + paint(0, x, y, w, h); +} + +void meow_ui_paint_full(void) +{ + paint(1, 0, 0, 0, 0); +} diff --git a/patch_v2/sdk/meow_ui_internal.h b/patch_v2/sdk/meow_ui_internal.h index 62dbf3c..bc3c89b 100644 --- a/patch_v2/sdk/meow_ui_internal.h +++ b/patch_v2/sdk/meow_ui_internal.h @@ -184,6 +184,31 @@ void meow_widget_touch_refresh(void); void meow_ui_global_render(void); int meow_ui_global_hit(int x, int y); +/* ---- 绘制物注册表(meow_ui_draw.c,§6.2 绘制物注册表/z序/区域重画)---- + * 内部协作接口:widget.c 在 create 末尾自动注册、meow_widget_free 自动注销;view.c 在 + * meow_view_add_widget/meow_view_free 挂/摘 widget 与 view 的 z 深度源;live_btn 收敛查询 + * 是否已注册(已注册→走 invalidate 区域重画,否则回退单控件 flush)。 */ +struct meow_view; /* 仅前向声明;完整类型在 meow_ui_view.h */ + +void meow_draw_widget_register(struct meow_widget *w); /* create 末尾:自动注册(幂等) */ +void meow_draw_widget_unregister(struct meow_widget *w); /* meow_widget_free:自动注销 */ +int meow_draw_widget_registered(const struct meow_widget *w);/* 是否在注册表(live_btn 收敛用) */ +void meow_draw_widget_set_view(struct meow_widget *w, struct meow_view *v); /* 挂 view:重算 auto z */ +void meow_draw_view_register(struct meow_view *v); /* view create:注册绘制物(on_draw 用) */ +void meow_draw_view_unregister(struct meow_view *v); /* view free:注销 */ +int meow_draw_view_entered(const struct meow_view *v); /* view 是否已进入(绘制过滤参考) */ +void meow_draw_view_set_z(struct meow_view *v, int z); /* view 显式 z(z<=0=清除回退自动) */ + +/* 控件布局深度反推(meow_ui_draw.c 用;widget.c 实现,读 struct meow_widget 内部字段)。 + * 让绘制注册表在「无 meow_view 时」仍能从 W_LAYOUT children 反推子>父深度。 */ +int meow_widget_is_layout(const struct meow_widget *w); /* 1 = W_LAYOUT */ +int meow_widget_nchild(const struct meow_widget *w); /* 布局子项数 */ +const struct meow_widget *meow_widget_child_at(const struct meow_widget *w, int idx); + +/* 控件几何/归属访问器(meow_ui_draw.c 用:绘制物 rect 实时读 + owner 过滤)。 */ +int meow_widget_owner(const struct meow_widget *w); /* 创建时绑定的 Activity */ +void meow_widget_rect(const struct meow_widget *w, int out[4]); /* x,y,w,h */ + /* ---- IME(meow_ui_ime.c)---- */ /* 当前是否显示软键盘。 */ int meow_ime_active(void); diff --git a/patch_v2/sdk/meow_ui_view.c b/patch_v2/sdk/meow_ui_view.c new file mode 100644 index 0000000..9ab349d --- /dev/null +++ b/patch_v2/sdk/meow_ui_view.c @@ -0,0 +1,197 @@ +/* + * meow_ui_view.c — meow_view 视图/页面框架骨架(§A 视图数据结构/嵌套/生命周期/页面导航)。 + * + * meow_view 是**薄壳**:容器 + 生命周期 + 事件路由;叶子仍是 meow_widget(不改)。绘制走 + * z 序绘制物注册表(on_draw 回调,非保留——不缓存像素)。opt-in:不调 meow_view_* 的 App + * 完全照旧(widget/activity/flush 不动)。页面模型 = 定案 b(顶层页切走 activity 栈, + * page_push/pop/replace 包装;不做页内子导航栈,sub_push/pop 为预留扩展位 a 桩)。 + */ +#include "meow_ui.h" +#include "meow_ui_internal.h" +#include "meow_ui_view.h" +#include +#include + +#define MEOW_VIEW_BY_ID_MAX 32 + +static meow_view *g_view_by_id[MEOW_VIEW_BY_ID_MAX]; /* id → 顶层页 view(page_push/pop 查找) */ +static meow_view *g_top_view = NULL; /* 当前进入的顶层页 view(生命周期跟踪) */ + +static void run_fn(meow_view_fn f, meow_view *v) +{ + if (f) f(v, v->ctx); +} + +/* 登记/清除 id→view 映射(幂等)。 */ +static void view_map_set(meow_view *v) +{ + if (!v) return; + int id = v->id; + if (id >= 0 && id < MEOW_VIEW_BY_ID_MAX) g_view_by_id[id] = v; +} +static void view_map_clear(meow_view *v) +{ + if (!v) return; + int id = v->id; + if (id >= 0 && id < MEOW_VIEW_BY_ID_MAX && g_view_by_id[id] == v) g_view_by_id[id] = NULL; +} +static meow_view *view_map_get(int id) +{ + return (id >= 0 && id < MEOW_VIEW_BY_ID_MAX) ? g_view_by_id[id] : NULL; +} + +/* 进入一个 view(置 ENTERED + on_enter)。 */ +static void view_enter(meow_view *v) +{ + if (!v || (v->state & MEOW_VIEW_STATE_ENTERED)) return; + v->state |= MEOW_VIEW_STATE_ENTERED; + run_fn(v->hooks.on_enter, v); +} +/* 离开一个 view(清 ENTERED + on_leave;默认不销毁子 view/widget——弹回零重建)。 */ +static void view_leave(meow_view *v) +{ + if (!v || !(v->state & MEOW_VIEW_STATE_ENTERED)) return; + v->state &= ~MEOW_VIEW_STATE_ENTERED; + run_fn(v->hooks.on_leave, v); +} + +/* ============================================================ */ +/* 生命周期 */ +/* ============================================================ */ +meow_view *meow_view_create(int id, meow_view_type type, + const meow_view_hooks *hooks, void *ctx) +{ + meow_view *v = (meow_view *)calloc(1, sizeof *v); + if (!v) return NULL; + v->id = id; + v->type = (type == MEOW_VIEW_CONTAINER) ? MEOW_VIEW_CONTAINER : MEOW_VIEW_ACTIVITY; + v->x = v->y = v->w = v->h = 0; + v->z = 0; + v->state = MEOW_VIEW_STATE_CREATED; + if (hooks) v->hooks = *hooks; + v->ctx = ctx; + view_map_set(v); + meow_draw_view_register(v); /* 登记为绘制物(on_draw 经 z 序重画触发) */ + run_fn(v->hooks.on_create, v); + if (v->hooks.on_layout) run_fn(v->hooks.on_layout, v); /* 布局:create 后跑一次 */ + return v; +} + +void meow_view_free(meow_view *v) +{ + if (!v) return; + if (v->state & MEOW_VIEW_STATE_ENTERED) view_leave(v); + run_fn(v->hooks.on_destroy, v); /* 释放视图态资源 */ + view_map_clear(v); + meow_draw_view_unregister(v); /* 注销 z 序绘制物 */ + for (int i = 0; i < v->nwidgets; i++) /* 叶子控件 */ + meow_widget_free(v->widgets[i]); + v->nwidgets = 0; + for (int i = 0; i < v->nchildren; i++) /* 子 view 递归 */ + meow_view_free(v->children[i]); + v->nchildren = 0; + free(v); +} + +/* ============================================================ */ +/* 嵌套(组合视图树) */ +/* ============================================================ */ +int meow_view_add_child(meow_view *parent, meow_view *child) +{ + if (!parent || !child || child == parent) return -1; + for (int i = 0; i < parent->nchildren; i++) + if (parent->children[i] == child) return -1; /* 去重 */ + if (parent->nchildren >= MEOW_VIEW_MAX_CHILD) return -1; + parent->children[parent->nchildren++] = child; + child->parent = parent; + return 0; +} + +int meow_view_add_widget(meow_view *v, meow_widget *w) +{ + if (!v || !w) return -1; + for (int i = 0; i < v->nwidgets; i++) + if (v->widgets[i] == w) return -1; + if (v->nwidgets >= MEOW_VIEW_MAX_WIDGET) return -1; + v->widgets[v->nwidgets++] = w; + meow_draw_widget_set_view(w, v); /* z 深度源 = view 树;重算 auto z */ + return 0; +} + +void meow_view_set_z(meow_view *v, int z) +{ + if (!v) return; + v->z = (z < 0) ? 0 : z; + meow_draw_view_set_z(v, v->z); +} +int meow_view_z(const meow_view *v) +{ + return v ? v->z : 0; +} + +/* ============================================================ */ +/* 页面导航(包装 activity 栈——唯一驱动 on_enter/on_leave) */ +/* ============================================================ */ +void meow_view_page_push(int id) +{ + meow_view *cur = g_top_view; + meow_view *next = view_map_get(id); + if (cur && cur != next) view_leave(cur); + meow_ui_activity_push(id); + view_enter(next); + g_top_view = next ? next : cur; +} + +void meow_view_page_pop(void) +{ + meow_view *cur = g_top_view; + view_leave(cur); + meow_ui_activity_pop(); + meow_view *next = view_map_get(meow_ui_activity_active()); + view_enter(next); + g_top_view = next ? next : NULL; +} + +/* 说明(诚实):replace 假定目标页已由 App 先 meow_view_create 指定 id 建好;本批不销毁旧页 + * 对象(保留弹回),仅 leave+enter 切换——与设计「leave+destroy 当前」的差异见汇报。 */ +void meow_view_page_replace(int id) +{ + meow_view *cur = g_top_view; + meow_view *next = view_map_get(id); + if (cur && cur != next) view_leave(cur); + view_enter(next); + g_top_view = next ? next : cur; +} + +/* ---- 页内子导航(预留扩展位 a 桩:本批不实现,仅返回占位)---- */ +int meow_view_sub_push(meow_view *v, meow_view *sub) +{ + (void)v; (void)sub; + return 0; /* 预留:将来在 ACTIVITY view 内维护子栈 */ +} +meow_view *meow_view_sub_pop(meow_view *v) +{ + (void)v; + return NULL; /* 预留 */ +} + +/* ============================================================ */ +/* 坐标 / 查询 */ +/* ============================================================ */ +int meow_view_screen_x(const meow_view *v) +{ + int x = v ? v->x : 0; + const meow_view *p = v ? v->parent : NULL; + while (p) { x += p->x; p = p->parent; } + return x; +} +int meow_view_screen_y(const meow_view *v) +{ + int y = v ? v->y : 0; + const meow_view *p = v ? v->parent : NULL; + while (p) { y += p->y; p = p->parent; } + return y; +} + +meow_view *meow_view_parent(const meow_view *v) { return v ? v->parent : NULL; } +int meow_view_get_state(const meow_view *v) { return v ? (int)v->state : 0; } diff --git a/patch_v2/sdk/meow_ui_view.h b/patch_v2/sdk/meow_ui_view.h new file mode 100644 index 0000000..0b221b9 --- /dev/null +++ b/patch_v2/sdk/meow_ui_view.h @@ -0,0 +1,98 @@ +/* + * meow_ui_view.h — SDK 视图/页面框架(meow_view,嵌套容器 + 生命周期 + 事件路由)。 + * + * 源:devdocs/plan/SDK_VIEW_FRAMEWORK_DESIGN.md §A。本文件为机制 ABI(结构 + 生命周期钩子 + + * 页面导航包装),与 z 序绘制物注册表(meow_ui_draw.c,§C/§6.2)协同: + * - meow_view 是**薄壳**:容器 + 生命周期 + 事件路由;叶子仍是 meow_widget(不改)。 + * - on_draw 是回调,view 不缓存像素(非保留);重绘由 meow_ui_invalidate 触发。 + * - opt-in:不调用 meow_view_* 的 App 完全照旧(widget/activity/flush 不动)。 + * - z 深度源 = view 树(parent/children 深度);叶子 widget 深度 = 所属 view 深度 + 1。 + * + * 页面模型(定案 b,预留 a):顶层页切换仍由 activity 栈(meow_view_page_push/pop/replace 包装), + * 不做页内子导航栈;meow_view_sub_push/pop 为将来扩展位(仅在一个 ACTIVITY view 内维护子栈)。 + */ +#ifndef MEOW_UI_VIEW_H +#define MEOW_UI_VIEW_H + +#include "meow_ui.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct meow_view meow_view; + +typedef enum { MEOW_VIEW_ACTIVITY = 0, MEOW_VIEW_CONTAINER = 1 } meow_view_type; +typedef enum { + MEOW_VIEW_STATE_CREATED = 1u << 0, + MEOW_VIEW_STATE_ENTERED = 1u << 1, + MEOW_VIEW_STATE_DIRTY = 1u << 2, +} meow_view_state; + +/* 生命周期/事件钩子(on_create→on_enter→(事件循环)→on_leave→on_destroy + on_layout)。 + * 均以 view 自身 + ctx(=视图控制器,业务-UI 绑定点)为参。可 NULL。 */ +typedef void (*meow_view_fn)(meow_view *v, void *ctx); +typedef int (*meow_view_ev_fn)(meow_view *v, int ev, int a, int b, void *ctx); +typedef void (*meow_view_draw_fn)(meow_view *v, const meow_theme *th, void *ctx); + +typedef struct meow_view_hooks { + meow_view_fn on_create; /* 建 view 后跑一次(分配视图态/初始布局) */ + meow_view_fn on_enter; /* 页面进入(push/replace 后;回页面自动恢复零重建) */ + meow_view_fn on_leave; /* 页面离开(pop/replace 前;默认不销毁子 view/widget) */ + meow_view_fn on_destroy; /* meow_view_free 释放(递归)时跑 */ + meow_view_fn on_layout; /* 布局(on_create/page_push 后跑一次,算子控件绝对坐标) */ + meow_view_draw_fn on_draw; /* 绘制回调(非保留;由 meow_ui_invalidate 触发) */ + meow_view_ev_fn on_event; /* 事件路由(可 NULL;先发后代按 z 降序,命中即消费) */ +} meow_view_hooks; + +#define MEOW_VIEW_MAX_CHILD 16 +#define MEOW_VIEW_MAX_WIDGET 32 + +struct meow_view { + int type; /* MEOW_VIEW_ACTIVITY / MEOW_VIEW_CONTAINER */ + int id; /* 页面/视图 id(App 命名的稳定值;= page_push 用的 id) */ + int x, y, w, h; /* 自身坐标(相对父内容原点;子 view 默认占满,叠放由 z 排) */ + meow_view *parent; + meow_view *children[MEOW_VIEW_MAX_CHILD]; + int nchildren; + meow_widget *widgets[MEOW_VIEW_MAX_WIDGET]; /* 叶子控件(直接挂本 view) */ + int nwidgets; + int z; /* 显式 z(meow_view_set_z);0=未设(由子/注册表推导) */ + unsigned state; /* meow_view_state 位掩码 */ + meow_view_hooks hooks; + void *ctx; /* 视图控制器(biz-UI 绑定点) */ +}; + +/* ---- 生命周期 ---- */ +meow_view *meow_view_create(int id, meow_view_type type, + const meow_view_hooks *hooks, void *ctx); +void meow_view_free(meow_view *v); /* 递归 on_destroy + widget_free 叶子 + 注销 z 序 */ + +/* ---- 嵌套(组合视图树)---- */ +int meow_view_add_child(meow_view *parent, meow_view *child); /* 任意深挂子 view;0/负=结果 */ +int meow_view_add_widget(meow_view *v, meow_widget *w); /* 挂叶子控件(登记 z 深度源) */ +void meow_view_set_z(meow_view *v, int z); /* 显式 z(999 置顶);影响其绘制物 z */ +int meow_view_z(const meow_view *v); + +/* ---- 页面导航(包装 activity 栈,唯一驱动 on_enter/on_leave——单一入口,App 不再分别调)---- + * 顶层页切换走 activity 栈;页内子导航为预留(见设计定案 b)。 */ +void meow_view_page_push(int id); /* activity_push + 旧top on_leave + 新页 on_enter */ +void meow_view_page_pop(void); /* 旧top on_leave + activity_pop + 新top on_enter */ +void meow_view_page_replace(int id); /* 旧top on_leave + 新页 on_enter(目标页须已 create) */ + +/* ---- 页内子导航(预留扩展位 a;本批为空实现/桩,仅在 ACTIVITY view 内维护子栈)---- */ +int meow_view_sub_push(meow_view *v, meow_view *sub); /* 预留;返回 0(未实现于本批) */ +meow_view *meow_view_sub_pop(meow_view *v); /* 预留;返回 NULL(未实现于本批) */ + +/* ---- 坐标:view 相对父内容原点的累计(父坐标链求和 → 屏幕绝对坐标)---- */ +int meow_view_screen_x(const meow_view *v); +int meow_view_screen_y(const meow_view *v); + +/* ---- 查询 ---- */ +meow_view *meow_view_parent(const meow_view *v); +int meow_view_get_state(const meow_view *v); /* MEOW_VIEW_STATE_* 位掩码 */ + +#ifdef __cplusplus +} +#endif +#endif /* MEOW_UI_VIEW_H */ diff --git a/patch_v2/sdk/meow_ui_widget.c b/patch_v2/sdk/meow_ui_widget.c index c6a473f..0881ae8 100644 --- a/patch_v2/sdk/meow_ui_widget.c +++ b/patch_v2/sdk/meow_ui_widget.c @@ -211,10 +211,16 @@ static meow_widget *live_btn_hit(int x, int y) return r; } -/* 重绘并局部刷新一个按钮区(绘制内部调 meow_gfx_fill_round 已标脏;flush_region 合区+上屏)。 */ +/* 重绘并局部刷新一个按钮区。 + * §6.2 收敛:若按钮已注册绘制物 → 走 meow_ui_invalidate(清底 + 按 z 重画重叠区完整 z 栈), + * 避免按钮压上层 chrome 时被单控件 flush 抹掉(P1);未注册则回退单控件绘制+区域上屏。 */ static void live_btn_redraw(meow_widget *w) { if (!w) return; + if (meow_draw_widget_registered(w)) { + meow_ui_invalidate(w->x, w->y, w->w, w->h); + return; + } meow_widget_draw(w); meow_ui_flush_region(w->x, w->y, w->w, w->h); } @@ -275,6 +281,7 @@ meow_widget *meow_btn_create(int x, int y, int w, int h, const char *label) t->state = MEOW_WS_ENABLED; /* §5.8.3:默认 ENABLED */ if (label) { strncpy(t->label, label, sizeof t->label - 1); t->label[sizeof t->label - 1] = 0; } live_btn_register(t); + meow_draw_widget_register(t); /* §6.2 自动注册(创建即注册,App 零调用) */ return t; } @@ -286,6 +293,7 @@ meow_widget *meow_slider_create(int x, int y, int w, int min, int max, int val) t->owner = meow_ui_activity_active(); t->state = MEOW_WS_ENABLED; t->min = min; t->max = (max > min) ? max : min + 1; t->val = (val < min) ? min : (val > t->max) ? t->max : val; + meow_draw_widget_register(t); return t; } @@ -298,6 +306,7 @@ meow_widget *meow_switch_create(int x, int y, int on) t->state = MEOW_WS_ENABLED; t->on = on ? 1 : 0; if (t->on) t->state |= MEOW_WS_SELECTED; /* §5.8.3:开关 on → selected */ + meow_draw_widget_register(t); return t; } @@ -310,12 +319,14 @@ meow_widget *meow_list_create(int x, int y, int w, int h, int count, t->owner = meow_ui_activity_active(); t->state = MEOW_WS_ENABLED; t->count = count; t->src = src; t->ctx = ctx; t->sel = 0; + meow_draw_widget_register(t); return t; } void meow_widget_free(meow_widget *w) { if (!w) return; + meow_draw_widget_unregister(w); /* §6.2:绘制物注册表自动注销(stale id 失效勿用) */ live_btn_unregister(w); free(w); } @@ -334,6 +345,7 @@ meow_widget *meow_widget_custom_create(int x, int y, int w, int h, t->render_cb = render_cb; t->hit_cb = hit_cb; t->ctx = ctx; + meow_draw_widget_register(t); return t; } @@ -346,6 +358,7 @@ meow_widget *meow_row_create(int x, int y, int w, int h, int spacing) t->owner = meow_ui_activity_active(); t->state = MEOW_WS_ENABLED; t->spacing = spacing > 0 ? spacing : 0; + meow_draw_widget_register(t); return t; } meow_widget *meow_column_create(int x, int y, int w, int h, int spacing) @@ -356,6 +369,7 @@ meow_widget *meow_column_create(int x, int y, int w, int h, int spacing) t->owner = meow_ui_activity_active(); t->state = MEOW_WS_ENABLED; t->spacing = spacing > 0 ? spacing : 0; + meow_draw_widget_register(t); return t; } meow_widget *meow_box_create(int x, int y, int w, int h) @@ -366,6 +380,7 @@ meow_widget *meow_box_create(int x, int y, int w, int h) t->owner = meow_ui_activity_active(); t->state = MEOW_WS_ENABLED; t->spacing = 0; + meow_draw_widget_register(t); return t; } meow_widget *meow_layout_spacer(int w, int h) @@ -375,6 +390,7 @@ meow_widget *meow_layout_spacer(int w, int h) t->type = W_SPACER; t->x = 0; t->y = 0; t->w = w > 0 ? w : 0; t->h = h > 0 ? h : 0; t->owner = meow_ui_activity_active(); t->state = MEOW_WS_ENABLED; + meow_draw_widget_register(t); return t; } @@ -421,6 +437,24 @@ void meow_layout_arrange(meow_widget *layout) } } +/* ---- 布局深度反推访问器(meow_ui_draw.c 用,读本 TU 的 struct meow_widget 内部字段)---- */ +int meow_widget_is_layout(const meow_widget *w) +{ return w && w->type == W_LAYOUT; } +int meow_widget_nchild(const meow_widget *w) +{ return (w && w->type == W_LAYOUT) ? w->nchildren : 0; } +const meow_widget *meow_widget_child_at(const meow_widget *w, int idx) +{ return (w && w->type == W_LAYOUT && idx >= 0 && idx < w->nchildren) ? w->children[idx] : NULL; } + +/* ---- 几何/归属访问器(meow_ui_draw.c 用:绘制物 rect 实时读 + owner 过滤)---- */ +int meow_widget_owner(const meow_widget *w) +{ return w ? w->owner : 0; } +void meow_widget_rect(const meow_widget *w, int out[4]) +{ + if (!out) return; + if (!w) { out[0] = out[1] = out[2] = out[3] = 0; return; } + out[0] = w->x; out[1] = w->y; out[2] = w->w; out[3] = w->h; +} + /* ============================================================ */ /* §5.8.6 batch2 Material 组件子集 API(create/setter/getter/hit) */ /* ============================================================ */ @@ -460,6 +494,7 @@ meow_widget *meow_textfield_create(int x, int y, int w, int h, const char *place t->buf = buf; t->buflen = buf ? (int)strlen(buf) : 0; t->maxlen = (maxlen > 0 && maxlen <= 256) ? maxlen : 256; t->ime_mode = mode; + meow_draw_widget_register(t); return t; } void meow_textfield_set_placeholder(meow_widget *w, const char *placeholder) @@ -515,6 +550,7 @@ meow_widget *meow_card_create(int x, int y, int w, int h) t->type = W_CARD; t->x = x; t->y = y; t->w = w; t->h = h; t->owner = meow_ui_activity_active(); t->state = MEOW_WS_ENABLED; + meow_draw_widget_register(t); return t; } void meow_card_set_content(meow_widget *card, meow_widget *child) @@ -535,6 +571,7 @@ meow_widget *meow_divider_create(int x, int y, int len, int vertical) t->owner = meow_ui_activity_active(); t->state = MEOW_WS_ENABLED; t->variant = vertical ? 1 : 0; + meow_draw_widget_register(t); return t; } @@ -547,6 +584,7 @@ meow_widget *meow_badge_create(int cx, int cy) t->owner = meow_ui_activity_active(); t->state = MEOW_WS_ENABLED; t->value = 0; /* 红点 */ + meow_draw_widget_register(t); return t; } void meow_badge_set(meow_widget *w, int count) @@ -564,6 +602,7 @@ meow_widget *meow_checkbox_create(int x, int y) t->type = W_CHECKBOX; t->x = x; t->y = y; t->w = 34; t->h = 34; t->owner = meow_ui_activity_active(); t->state = MEOW_WS_ENABLED; + meow_draw_widget_register(t); return t; } meow_widget *meow_radio_create(int x, int y) @@ -573,6 +612,7 @@ meow_widget *meow_radio_create(int x, int y) t->type = W_RADIO; t->x = x; t->y = y; t->w = 34; t->h = 34; t->owner = meow_ui_activity_active(); t->state = MEOW_WS_ENABLED; + meow_draw_widget_register(t); return t; } @@ -586,6 +626,7 @@ meow_widget *meow_progress_create(int x, int y, int w, int h, int value) t->state = MEOW_WS_ENABLED; t->variant = 0; /* 线性 */ t->value = value < 0 ? -1 : (value > 100 ? 100 : value); + meow_draw_widget_register(t); return t; } meow_widget *meow_progress_circular_create(int cx, int cy, int r, int value) @@ -603,6 +644,7 @@ meow_widget *meow_progress_circular_create(int cx, int cy, int r, int value) t->state = MEOW_WS_ENABLED; t->variant = 1; /* 圆形 */ t->value = value < 0 ? -1 : (value > 100 ? 100 : value); + meow_draw_widget_register(t); return t; } void meow_progress_set(meow_widget *w, int value) @@ -621,6 +663,7 @@ meow_widget *meow_fab_create(int x, int y, int size, const char *label) t->owner = meow_ui_activity_active(); t->state = MEOW_WS_ENABLED; if (label) { strncpy(t->label, label, sizeof t->label - 1); t->label[sizeof t->label - 1] = 0; } + meow_draw_widget_register(t); return t; } @@ -634,6 +677,7 @@ meow_widget *meow_topappbar_create(int x, int y, int w, int h, const char *title t->state = MEOW_WS_ENABLED; t->back_on = 0; t->nitems = 0; if (title) { strncpy(t->label, title, sizeof t->label - 1); t->label[sizeof t->label - 1] = 0; } + meow_draw_widget_register(t); return t; } void meow_topappbar_set_title(meow_widget *w, const char *title) @@ -682,6 +726,7 @@ meow_widget *meow_navigationbar_create(int x, int y, int w, int h) t->owner = meow_ui_activity_active(); t->state = MEOW_WS_ENABLED; t->nitems = 0; t->selected = 0; + meow_draw_widget_register(t); return t; } int meow_navigationbar_add_item(meow_widget *w, const char *label) @@ -721,6 +766,7 @@ meow_widget *meow_tabbar_create(int x, int y, int w, int h) t->owner = meow_ui_activity_active(); t->state = MEOW_WS_ENABLED; t->nitems = 0; t->selected = 0; + meow_draw_widget_register(t); return t; } int meow_tabbar_add_tab(meow_widget *w, const char *label) diff --git a/patch_v2/sdk/test_ime_fix.c b/patch_v2/sdk/test_ime_fix.c index ba170aa..74f5891 100644 --- a/patch_v2/sdk/test_ime_fix.c +++ b/patch_v2/sdk/test_ime_fix.c @@ -8,6 +8,7 @@ * gcc -Wall -Wextra -o test_ime_fix test_ime_fix.c test_host_stub.c \ * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \ + * meow_ui_draw.c meow_ui_view.c \ * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread */ #include "meow_ui.h" diff --git a/patch_v2/sdk/test_meow_ui_widgets.c b/patch_v2/sdk/test_meow_ui_widgets.c index 4b1b447..18d4c59 100644 --- a/patch_v2/sdk/test_meow_ui_widgets.c +++ b/patch_v2/sdk/test_meow_ui_widgets.c @@ -5,6 +5,7 @@ * gcc -o test_meow_ui_widgets test_meow_ui_widgets.c test_host_stub.c \ * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \ + * meow_ui_draw.c meow_ui_view.c \ * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread * 运行:MEOW_UI_DUMP=/tmp/b2.ppm ./test_meow_ui_widgets (可选,dump 屏幕) */ diff --git a/patch_v2/sdk/test_p1p2p3_repro.c b/patch_v2/sdk/test_p1p2p3_repro.c index eaefad4..f8e89f2 100644 --- a/patch_v2/sdk/test_p1p2p3_repro.c +++ b/patch_v2/sdk/test_p1p2p3_repro.c @@ -18,12 +18,13 @@ * -o test_p1p2p3_repro test_p1p2p3_repro.c test_host_stub.c \ * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \ - * meow_ui_img.c meow_ui_config.c meow_ui_notify.c meow_notify_ipc.c stb_image.c \ + * meow_ui_img.c meow_ui_config.c meow_ui_notify.c meow_notify_ipc.c meow_ui_draw.c \ + * meow_ui_view.c stb_image.c \ * -I. -I../hello_app -I../meow_launcherd -pthread -lm * 运行:MEOW_UI_DUMP=/tmp/repro.ppm ./test_p1p2p3_repro (optional,dump 最终屏幕) * - * 修复前(无 P1/P2/P3 修法)预期输出:RESULT: 4 FAIL(S); - * 修复后:RESULT: ALL PASS。 + * 覆盖(批次① z 序下沉后):P1c 显式 z 置顶(set_z(g_fab,999)+invalidate(r_prc) 不抹 FAB—— + * 显式 z 不依赖绘制先后)+ P2/P3 与迁移前一致。预期 RESULT: ALL PASS。 */ #include "meow_ui.h" #include "meow_ui_internal.h" @@ -74,13 +75,15 @@ int main(void) int fails = 0; - /* ================= P1:局部重绘不盖浮层(FAB) ================= - * 场景:scroll=0 时圆形进度(413..453,605..645) 与 FAB(406..462,616..672) 重叠。 - * demo_paint 先画内容后画 chrome → 场景正确 FAB 在上。随后「局部重绘进度条」: + /* ================= P1 / P1c:局部重绘不盖浮层(FAB,须显式置顶) ================= + * 场景:scroll=0 时圆形进度 r_prc(413..453,605..645) 与 FAB(406..462,616..672) 重叠。 + * demo_paint 整帧后 FAB 在上(demo_init set_z(g_fab,999) 显式置顶)。随后「局部重绘进度条」: * 旧(清底+只画进度条+flush 其矩形)→ FAB 重叠区被清掉; - * 新(清底+重画重叠区内所有控件=hello d_redraw/d_paint_region)→ FAB 保持。 */ + * 新(SDK meow_ui_invalidate:清底 + 按 z 重画重叠区完整 z 栈)→ FAB 保持。 + * P1c:set_z(g_fab,999) 后 invalidate(r_prc),断言 FAB 重叠点(434,622) 仍=demo_paint 后值 + * (显式 z 不依赖绘制先后——置顶在重绘前显式给出,下层重绘不抹上层)。 */ demo_paint(); - int fx = r_fab.x + 28, fy = r_fab.y + 6; /* FAB 内、远离 "+" 文本处 */ + int fx = r_fab.x + 28, fy = r_fab.y + 6; /* FAB 内、远离 "+" 文本处 → (434,622) */ int s0r, s0g, s0b; rd_px(fx, fy, &s0r, &s0g, &s0b); printf("P1 scene (demo_paint) FAB-overlap "); pr_px("scene", fx, fy); if (is_bg(s0r, s0g, s0b)) @@ -98,15 +101,16 @@ int main(void) if (is_bg(obr, obg, obb)) printf(" [BUG-CONFIRMED] old path erased FAB overlap (bg)\n"); else printf(" [note] old path did NOT erase FAB here (color %02X%02X%02X)\n", obr, obg, obb); - /* 新式局部重绘(真实 hello d_redraw → d_paint_region,重画重叠栈)*/ + /* P1c:显式置顶 + SDK 局部重画(invalidate 按 z 重画重叠栈) */ demo_paint(); /* 还原场景 */ + meow_widget_set_z(g_fab, 999); /* 重新显式置顶(P1c 要求) */ meow_progress_set(g_dprc, 30); - d_redraw(g_dprc, r_prc); /* hello 的局部重绘入口 */ + meow_ui_invalidate(r_prc.x, r_prc.y, r_prc.w, r_prc.h); int nbr, nbg, nbb; rd_px(fx, fy, &nbr, &nbg, &nbb); - printf("P1 new-partial (d_redraw stack) "); pr_px("new", fx, fy); + printf("P1c set_z(999)+invalidate(r_prc) "); pr_px("p1c", fx, fy); if (near(s0r, nbr) && near(s0g, nbg) && near(s0b, nbb)) - printf(" P1-PASS FAB preserved over live progress redraw\n"); - else { printf(" P1-FAIL FAB not preserved (scene %02X%02X%02X vs new %02X%02X%02X)\n", + printf(" P1-PASS explicit z:FAB preserved over live progress redraw\n"); + else { printf(" P1-FAIL FAB not preserved (scene %02X%02X%02X vs p1c %02X%02X%02X)\n", s0r, s0g, s0b, nbr, nbg, nbb); fails++; } /* ================= P2:列表焦点按本次触摸绑定/释放 ================= @@ -128,7 +132,7 @@ int main(void) printf("P3 list rect = (%d,%d,%d,%d)\n", r_list.x, r_list.y, r_list.w, r_list.h); /* 顶部泄漏:选中行0 + scroll=20 → 行0 ry=top-20,填充越顶泄漏 */ meow_list_set_selected(g_dlc, 0); meow_list_set_scroll(g_dlc, 20); - d_redraw(g_dlc, r_list); + meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); int ux = r_list.x + 10, uy = r_list.y - 5; /* 列表顶上方 5px(标题间隙) */ int ur, ug, ub; rd_px(ux, uy, &ur, &ug, &ub); printf("P3 top-leak "); pr_px("above-top", ux, uy); @@ -136,7 +140,7 @@ int main(void) else { printf(" P3-top-FAIL leaked into title gap\n"); fails++; } /* 底部泄漏:选中行4 + scroll=20 → 行4 ry=590..630 越底泄漏 */ meow_list_set_selected(g_dlc, 4); meow_list_set_scroll(g_dlc, 20); - d_redraw(g_dlc, r_list); + meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); int dx = r_list.x + 10, dy_ = r_list.y + r_list.h + 5; /* 列表底下方 5px */ int dr, dg, db; rd_px(dx, dy_, &dr, &dg, &db); printf("P3 bot-leak "); pr_px("below-bottom", dx, dy_); diff --git a/patch_v2/sdk/test_sdk_fixes.c b/patch_v2/sdk/test_sdk_fixes.c index e2a3401..311396c 100644 --- a/patch_v2/sdk/test_sdk_fixes.c +++ b/patch_v2/sdk/test_sdk_fixes.c @@ -10,6 +10,7 @@ * gcc -Wall -o test_sdk_fixes test_sdk_fixes.c test_host_stub.c \ * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \ + * meow_ui_draw.c meow_ui_view.c \ * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread */ #include "meow_ui.h"