From c6b7d2a5cc1fe4ca508d1b1352b12f5b2eca1c08 Mon Sep 17 00:00:00 2001 From: Chuck <33324927+ChuckBuilds@users.noreply.github.com> Date: Wed, 23 Jul 2025 11:24:10 -0500 Subject: [PATCH] switching to TTF font --- assets/fonts/dot_digital-7.ttf | Bin 0 -> 49964 bytes src/of_the_day_manager.py | 87 +++++++++------------------------ 2 files changed, 24 insertions(+), 63 deletions(-) create mode 100644 assets/fonts/dot_digital-7.ttf diff --git a/assets/fonts/dot_digital-7.ttf b/assets/fonts/dot_digital-7.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2757a91ec8c48140db1e43b613225295178d4811 GIT binary patch literal 49964 zcmeHQ378#Kl|HxA**p8b5MCBS0$F-Vx;sq>0YcbA7C;0HG)ad9LJ~V+2`VBgVnmGS zL`IQ8bQnb35E(}q7jzuPK}1Ez1rZT3A|fg}7$tB1|DHOx?yI*pW)#1#tGn*Kb*t*0 z|NQ6Nb8pqFdQY5)G|1J`N0y$pW`6U!U;gPn5qAP=&p&h7sb^gdu5*+(SAL)XKcJ=#}&iQL`mEoBK3PWZ(Y}U)S@xxihTMmk-Ez+>AYf_ zTPttJ{#iIEx25xvu1%kQ>YE~;fxP z?6a4xf4yPZi<+;xKqTK@x2q01%0Q`OEf${n- z@)O@y4zk%M7Up4Hi+0aK^flAq2)Mf+>5_w9U1<+AKo!@>5RPcUWL z{%gxOj?k}_qdCYUUJ7hVerU&Jt;9uHJz`s-T=qEf65*&MtJJ=-?e;`|#x~{Tl$AwJ z6CHSr=NkNCapJgORC-}RUIs|N{C>ph{zwP;bg&G_zlgm9kq(hTNQe4#m<&dFxHRPd zEF*k6Qih;BN`@jG?b9(bEdM7NE5nhFlMzVA`*ebgM0ui&%I}j&KAkM1Q9ek~kCKydNTG9H> z|Baj=El5w41xQcw>B+JX92g z$YPYwlq2)c$}4<&mMlT}m2wo)vweDwEY1H)&XuE)zDkZky4I)X$+0M(FU#`JNT*LP zkmFEZC(Dtp_i2|LpZ}$7kQ0zzC?_J_=+jMd63Q3J$@!<{VxMl7Q&7G{PDQ%Kr(0!3 z{ui=MPDA=?S&6jUr`u%}$~$Crey?2W)5~NH%9qRONU!kePB|n0bGcH^MEV+e1=830 z^mTF;%2&xN^H0g^eR{Q=jq)4h9HiIy^o??E{%7(gc@@$(%UYz@`t&Vw9?I9r`S~a1 ztv=l)ohZLeE0?wF#m+S%ct*_jVS+vY(l!n zr|*%A@;{NAim!8Ht9zC zLD`Plp8SVTzbbD-`9I})q!0M? zzvS)t|BeDCXR+N7xA3*w)Pk%1A<-aL=<%39nAs<5ev`>F2|BUi8a(n(^`IS$f zm489`*K!Ba=Y0Ab`EdRl@>{tR>F?wtNT2uV@8vF({~#aDKP3O_(--7pDF0DDj&z?- z|0JKte_j48pG5ki+>Lao*a;2<7bXub z+KK!I+&>SV_q#rBpd0FjxM6OD8}3HB(Qd38>93 znQoSwEnT>3dJG=(Cd93Gxdz0HYZ0%02EP&co#VB|4W7cs5hK#&33!XRQSK0U$Bz(m z#4YeUuS1kr4=epjo^y3>uA7HAcp0MOc0|ipJ6wyoIj#vuUWf>bt1&Dakxf^ z4L^BSUXb6zJN^W(_#=mR9FceZ-2m4Q=Pq=u{v0MxNxi!c`C?e09@dzS*m)=7!{>1P z8rSKra96n->%Lm|XnjNdu=>;L&#gbN{++qexrwa?yjk0r%uClsi2J+ zh*uv$Ou5gkcIV^l*Cl7W`l0p1>sQsUt>2v+l^dU%oXh#M7o}$-)(PT~V7&Zc{u}v! z%YQn5+y1Tl&qj^>8P}v-9={;TmptAs^5f6_`05{@0pDGW+ND@m>)t3m3uBF7eG}{< zSa&6MP;2l&^V~kL04?|i^!PX8_@ChDCt%eZ(BGegC2vGre>eF0Ic#u9i(0_d zeXXO~Daohgla#=063)^R@-Uh5TxYS;j# z{g0sT{^C09GJFI}DvUWTb4=p>odm1behg&rXf{Z7lKVJ&3iJsUBf5pj3NRi6GnE@S z(R)FeHpsPE-P$PMgtysx*lcaqX0#VklO1Er%7zJ4pr~|#zCA2rWokNR+x9xf?Xqp2 zz_awfN^ABqJuxmuzFjf;eC2I#~49tY|kIZ zYSbu~g}&>t_JK6EWoyP;GbX`I0*hN)VAm4;GVTrLgOpIJ9EeGr65B~h`KP0zWKK!u z)CQXR?t_^QmqPs%S3&PIOPl8~HwG1lr!fdC=%a%vqJr*TQnq(eg4xP)qJTni1Tqk+ zGN72c#KRt8DIoZJsAX{!=^Mv|LIkO>041$TVwA~M47JE61I8~kwUsz*Rqd%;us-SV zF$sCSbZ#xE z%4n84p{*kM>`9c*7Bb>{;A=4k#bLT250Fx4Gp;e~!&1_pbq?sqFY8xqnQPp$S&lp| z$V$wu;w|oAuX&vzP-eVsYKS}L`zFji$7 zMPcX+Z3%CQkQ6~fMa-JwGIa2&ffewTv>*E_SK=Wy2#D=QHzb~nTm~rb#WmQe)c9c9 z$9V-Nj1kKfVKEVAFv0zo%Dx=zRB8S|K4NaT9q3TgL~O--QfRadVWoL3V>&sbWaFeX z61EzQRV=S#D8F4k$f} z2eC)7Z0yEm^Ssg?2i@>btqXk5jIXLIKE+Io2cSR12w5(T4wzsTqEj=KvW|8Jrq$w= zjl*Ol_D#ySmGyxM2sP)7b3zI?YE*o1ky^Q7KQZ4l3mFE>&6*@$^#?Li5Q9lgrsDy^84d-;X;mU+Lh z;94o$^Q>KM5t370wZoOU&uac{$eDY%+7MFnUp7-4He}FSD4DMPcY-WUMpyEJUK{B52%QFpjFf zs_%l^igDB!GYrhlKZu9h5CE1`E>bQOpOLHX40$!!DeK*)c{Znw$}nLBSgr_*i3l{* z9@|UJ)(wgAW85gZgbt-BVk;0;z!g2mY@~U$IR*LRO3PG6LgNHu6^kztjDFR7J#8J| zyvKZoWNH~S^5e+W}nFt9>}gT$0*f9Eo#M1pG2!v zkXqCanLUdK*~r9x&ozz%ww-Ei!HGF^!+$}fC`EyKoZ_r$%wt?ITf`_!AuO~>j1Ek} zEUZy8Rf2~3Mh~um=npY2E3;k$rpmTX80UnPxfTm9QtLQFe#|G$LWaR|cbg6W^10@Z>mJL*=#m+%x|X@ShZScZ!^s|w};7QC3(Hh+qJ$uLd0iqhAA+{)gJhgVK95e+bTE}AGXO;1cJiViI_rul~_YtS!~IUzp9A$ z12mS%_R3O*%JDL)=t$mec1Ui`FSEIMCuof=AA3TUYgLszSDXhL0<&x>6s9foECC?x z6e^NO*B)bI?ajK>zFawC0^;yb4oa0`K1=}u^zf?rUfdtd7NrFuR6_Ch^ zqYSEIjZ(JNnXwQ1sTO=XiFbH=G=9#&p2hU~@hP&{0>ni5wh|je;$Ii49ppny-F?k3 z-r3hCzdp<~|fAV}2zL1Aitv&JAabQGFmD7z|ASsq7hP^k1&1#mbWZ zESt~jR~WaVXOLnPF-tL0D|=Cpp%9Q7xKcS0F7b!}%IAiaM%DY6HE~x8RgBuo3I{x8 z(e!{if3JKuzBNJLbMW>X2fv{T&3G5VkH309eSN}j;W5zKAA@lS?`!Xi-j@i+nZ14A zRyKXhB#HAC^x^oq=}PB$X?7l-Rg9mj4-vrlp^MOTWQY&XduL(XsP$QPe*W+P#z=ea zy~^hg`UE`K7>)C!ZdXNrY{Oe?N8wGi^x+VQ58CJ8=ncJ1eiewIm@53o|y>qw-eU?`{7U`JBn7Dm} z)BTKkTmTAPJRWJa67_`6!)!$$ThD8smkW-Uc)!c82hDn(fI=Fmdt$AEyNb#O2R7bM zDI90)J-~u-iZWtraNFdmNRW?zl>Jyl!A7^;ON+)%lQA8mBU<8W+AxnJJtdiou~i?& z5~UywBdwp6P$P2%#%qpkm_bKll-DP|lGE1IS^0**KKg{l#>#W8LJWQt>(`K$o1Z}B}lrTY+{cjg#ebPZ#O${~z3fFR#j z61vU81mGuS0X2@oc)Y)XJFu83Ea!=Uo5QvIMfjGiYM9e`!y3H9eh%J2UWa$UFUI@E z+wrzJ-!S%CWk1(4PEqyRJA1uLP0RTS+SdM#LR=1>kvg!s zf#&*N4ZgiBT-)lsOmEY1kQhs)bX5X+KnzkyMbDvHy835=@J#`Qeb)E(zBoJXm5R+b zgtka|LQl`$0Y%h0Kz{s2yj%aa+PyjUM)SzHF6-^_J}Z|x#_E_S#2}0RW6$cPx_6@cydv4%`Rv_iD25 z!>8Xf5auD)gW2oivTa+BC9j+-z_;Q>AVpD! zSj;n6X3R9q3MF`G2%JS8LHYCp%Mbj#;BR?dRYi8(*T|r;$8x+KctoM7=d-RL(xz0} zXNqNPT4d1!F5k~J|Hk8Q4bRq^9jJf2njOp*+((ZG zeMXlZe+^x^en+I%_Y-F!%;Nr+@ft&Coe}Zi<^GIzm1jWWYy3DeDMLQuAW3_Z_Mvp9 z!l8-R*BHku-|sEBzBc>Bo@3s_-0T+TFb=(G8_?jBLKr6e6P@mjQzBjB1Ey)g0Gh5n zv0e7+IXmwyW-et6FsphNamC?1y=PG-Ch>E>0l0ju~U-g_av@ z#*Q(i2(obuSW;}*AWB1}h+=ZWJ*aZ`af3Y#O`MlQ#$(8q-QOjKT5$3hEK0J$%v#gC zK{b2ET$;CKbD~T+)IO@BwOoohWf1;U^L?0@ueeO^3=yP4WR@Y@hQjLlSu>hB>EAWS zd&Z0y2g{}GSlP=U8vkhzNL((9(E1{C`+T|L^-FBG7^NXJRJJd*U+iOQ#RQYlSd2~4 z>9ti4=6bZ6$&Yi^2gzmZiRvtl;8L|*-<9Jh#=)}jRhl28#BxPl8W_7F{HwZIcwB_;FiNl+r6g``e9%qw4SBraJ~OtIN_ ztZ7`1z0v9e3MC;sob@YM9#6h2v{&z9;dhJd;GV{so*hbTdj5)%jl27K03!yGf* zF^H{X)-oKWa$v)((u|h)Oo`Fdx(scZKHy_OEeGDJ&&0={;~BzYwo*(*ETvOMiiJpg zqcWDvz5T-bRyt=qD!sE}l9|UIRIMC3Z%P$xhJX5gnNsTi%2RO)_#R{e;HL$MN2tCDaAC_l)pv_n#72S+IkY}E#k%OTR_*o1aojnsRmLXW|-1TdVKHA z@Gv(PnOoWRTOD%`ApJNLXo$i09TYX@04eKvjmA7hoZ|JWc=R>R9ZE%OqRBFtiPVG@ zk(UCAsjEH@EhRmULNSU+U}mgHx>M#(l^V~FS!%!CCC6d?F5()l3uD`rD#IM;#=rtz zl25JZ@%s4{4Trth#X3E%khDSzlE#|mH8#Q#k)euNV>#ZZ_$(p=Pp~2iR!y`Co3T9= zBH~RA^Q|nd7(>?kiLnq@1Oz(>2b3i~SBy+?!QE?`6O{5fqKjFh4;q_98_^UYQE0)Q zgc>m&$QEiAg+5<6EU`*BauR`4as-E?YlPG?0jYBGytEm$LKZLPtwG163ewPP?ki zku8SA@xsbPXuVeZp{6O9NjyVlP4<#2a(eRD4Q zbiC5PYmWE5_q`JKkR>ekFg{p3FiTp_`Vb$=*fRj|A&{C!nkx`Qx-xF`-uKF~lujAR6*=m??-k-9BaTI$TFUUv-uqq^@0-Ld zT90O(tyaezY-aCop*QCgf`?VX?WxoLj~I=(ML{<-M$(6j{3!`y+-?3R2^I6VKDou#p_*sLXv zPQYtEpq}8x=`BT6;6eI=-#@d+4;aby_M9^JL5n_-Xu!d7prfN@cz<05C=<4jOMiN;2qvuE+T# z-&u>lr$#>$^2d*hc!|*xo$&$?0UQtj&_0huaU^`;-RSb~DB4Vkt=byTUQMz}P49bn z9#nQfP`AsTmp7|~7{Plm<#Bj@Ie#_;u_qQH2*Oe*p(>THauey9_u?t1zvqya1Z6Y^ zzdxoOzZ3kBe^)`seR>R!1Af{I@1&RDvIsvhTd!hXXePFYE)>`zPX3{NUTc--so*;$ z$Q9*~E9T|Ou$2CTCq^c0Bqb$|btoAex{kRsjjZ!Hyer?scZEDB_DQPQm3eI2xLoQO z?&qo;;tdrKE>VHgBLHVG2p@k0Wm$z=C-f33=wENat7p`%P(RgG>sVHO$Mjg=HN~IY z#{I}NVNOfM+FF_WjG;oURW0)(KfXYDKA5Ywhl1KDl+m1e>r0oOGIE&M`GD$9olPIp z#kNg9+m83goLJc#&BLrT6i#Y)%GrpC39ZUEi0wn_wuJD+n~G z|6wybN_po>-p#G>y)nFx9>z(s7Oz?MxG%;62$1i6Bys*URAQg?2*n5rvR@{HDo+ck z@$b9-KjT#(2M}*^%~^$CKBw@KIi?NBd5^fp!Qd3?R%V<>*>&^FP6t&0X$?A<-;{fI zQJ<@Q$u@v{qOaHJH$wMocKP+=Qy5N9LYxN zQuP3o1{Qd={-;&gpHyL}QU%g*m{JdGgmB}hS^hevy~49n!DEQZkeL=7f4G_k5Uh(L z(3CX^P(bn*GV}@p(LWC)`Mk4g9}IX51M_(7w{62@#}PXKfu#U0+6oYLXVm8mX`J&! z%pLzKm}9^I_m^TG0o?o!h|=F1nZ8fK?^F1TxF+vC;vDe>y4Juv4+`8@j(0Dw@3QdM z%ebZ~$9)msm>O-F~2OXkUIwIQ(a+6>u(c-7>Pl0}_T31$HOFOPM zyf{iBSI291FBgkmfY8S+5zlWF}7O!m4PgpNUFD~-?B_)Bi}3geLpq!s~D?q zxkA5+FjneW_PI{EdAj#K`+j%Y&p0wH%!6G43QO7z3`DRdCqOYh@Ufac+sS^u6-y@~ zTPa@q9zd9M=AlbyXCw;kjCP~ge7(fyHu`(>85>cep)g*ubr1?cni`lQbf~ZZkuqZ? z@Y6$IH%yirGg)lhCT^eug6vEor7OAFsIb9VHeirPvuW>r#bTc@-{>*d>NeoLGUH_b zK+cED`N>Q27dQqKKw5(i=I7<-9tCqd^KZ+E&sM98xrdwf-dBuzYUDT7uKU70_1^o6 zh}6CJ6_cJ;>%CANI>Lw&4bU&?UTE)qMetuM_ZszT;2yEjrinVDb4+K9(40oIxmtz$ zXa!d)He&SNS1kNa1CC1NI5EyV_35OQrU*tve<~bQ)l6n8?1RyI?<lH7a&^3R zAF2G@zF_32#UHiT0z-*jRKTeXYvzZR(;xex&*RCe%y$`kEMw3oj2r96Je4{Jeh^>w z5rALNR_{H=5V0(Bfv)oY!I*2lQRV(;?>$EUBZ)dznGZ9k`}N*q^t`B}y^QZMChx45 zxepv-U_86e#zJnx;s`;0DGq>PCSQVwVeD|Ves5?kSNj$rIht6M1SEF;5F{01QU!0- ze@@NxkaSv>I(J+GLhsn8#gSt zm^(0L&LINhyA3hW*5|%g><57+H*&C8Ne9NK&5Y;ek*TP|GOOfJ$})Y+}*J z!};z0{FT8V+e_p3T(D(r1Q83TV`2Ejdt8~{bMa@4!_hp0y)``xaZt~MG@RSR=Q!>9 zERF!?K~`tE)kheTK%0rhj1W|)M72d?(Jx(*!Y_s##?xIYA|Cu=XAy! zZRlk|xSA_SBr(!s=J}?!9ERr&g}EvJ`dJ6 z)UT|+p#IAG8|yz?|8U>Bz9;m3ci$)bP42g`-@W~w@88k?y8d76zkk4z0ow-LKXB;4 zl>=`cxOdQkK|2QBK4|aYX@k25-!ph`Lu13a4OcbX*>HcuV-3#@Sv=(WAzv9feCXPt zHxGScSmUsb!)_n;)bR1cFB*RD@E1lb8?k%Dqa!DeTrqO@$gho>IO^O{yGMO*^q|p) zjXrnum7~8prhd%WF{h8&Hs-o9_l$XF?BcOkk9~OT-f>ID?Hc#p@w3M77=P{fo5tTW z{^9Y@OsJbMWx`Dp_D8e;|Fydv~S9iDI2C- zH|3Utw;g=+rg`s}P{W;f2hdiMQ?O+4)M!|pwN z+Tj}x|H_=YIm_qVHs{&79dmch{lUD3c^l{5JAdT-)$?zezpt^Q@tVd*nx-|aZ@Rl_ ze{*Z|#^$@4|J<^qWlzh)3z`?)vfzn@OBY_X@cz~*trxXk+xoS(0d1$Wt!>-g_DK84 z_8IN1?Hk+gSu|(SogFhf&hEJTh(SkeKH{OpGZ$aC_~|3(9eLf6Pb^u!zARjsR5tlGTlp;b?>=5?XS1lR0; z1%%~OvGNx|m=3{~mh14#+-E1{J~CN4lX5+dd0kTOi}J3d+z(ef?@7x2WtMy}DGxw9 z|DBWv$_V*ZQf`n5^3$X|L=KieC*_ec#7#ova`pVSjQ6@(N!iInAIDfs7nwzGTFg&TL|X04l@Yi?|6$z8BBw`RxA&0TZb=H-swygBE0Z_jmiZSU&7tZV(e z+{PU{wsp*(fBEH?&)d!ew|8CEwPoJAt(Pp@x+Ax2(}kOMbZ(y8wz})WOE-6RCrx$a z3U+pQQ3X|Jc6D#xv~^3aX(Ya-PS9e*s%e%X}F7NE_%5B)%o!bWSTeoy>&Rx2_E4Ova=AH8jpOJHba6v?KD1QMXk#AT88kUS@j@+PKnl!(aAO*1ItNbOIe)>-Ki*8N17I zRu}#*_ei?X>ISskjeMJLal6-@jOV~KtwXF^u)Py(;9XWO`JaQ$5{v6VXsW|e{Kdrq z_%_@@c(SGev1ceo+Tn;PBV`nR8+nY3m2om2ab==RLc}^qrXa55WU5S)=`uqOk(ror z&4Mo;hTqni1KZDo@6ack;gt(yp|rvq+GP>E>IhjZN6HesakUg)c?|q|nH(p}@vF)w z$cY%OPnJ^7z@@f1k-QDsjx!w(tFSwy@m>cd!xRGv@ z8!i9t#>if|){T|7xpDGg`H&kgyW9kMqrA&abd%g;_vJIo!9+1*?>&&_v@uE{mK7Pr7HbgizG!yVxkyCdBaca&S|j&{em zW8E@$oLlaWcPF?L-AV3bcZxgJt#GHgm2MU0DQn#6?hJRPdxbm8z0#fS&T;3uSK*%H zdG37I=`L{V+wP5U%->TEf32#<>Tn3&&fOGyYh&92R`~s`IWp?E`m2-j2^HV z-gGN`>ecW#_O?sWKQ4nmJ`K;l5?=Nij9Rai&&UVxE0$Nu)$#^;MxK?=$|vNL@}&Gs zJ||Df&*gUco_rtoPV1#_-+5au-Mo2V=Y~z2ni?AyHic4iQbKM0ahG;)4LjOHX_1v$ z!)dLJcG`l4ws(;o*VNc*dmGzADcx%=H!W(hb6W$9CTqEIp`F{fFw`}NGZwb=zjVu{ z#>S(USsM#YYU4t~)YKS`U(`Mn;eONB_3OH}?C9$5T5qSdsZy;?EeivPMpLw@(VA*p zxFD#K9%prpO#y6^sn^(KDmON#3RugH&DKg|b7-YGNNWztG>4X(L(9#f<(ANLOK7QZZwWG5f{d0Rqb0~_2{KxOj0Hi)f*@l-kg*`hSP*2SPO%`!SP*0^2r?D~8La_T zYdE7doY5N2Xboqy1ypSTOIyIw7O=F1mfJ$hZK371&~jU7xjnSp9`tPwGTMWT_8_A@ t$Y>8T+JlVtAfr9VSQKO|3NjW28EMB@6l5$4G8P3Hi}0Q@7MIV9{2$r{Zm|FW literal 0 HcmV?d00001 diff --git a/src/of_the_day_manager.py b/src/of_the_day_manager.py index d1377319..78ab328a 100644 --- a/src/of_the_day_manager.py +++ b/src/of_the_day_manager.py @@ -8,7 +8,6 @@ from rgbmatrix import graphics import pytz from src.config_manager import ConfigManager import time -import freetype # Configure logger for this module logger = logging.getLogger(__name__) @@ -37,10 +36,10 @@ class OfTheDayManager: self.last_rotation_time = time.time() self.last_category_rotation_time = time.time() - # Load fonts using freetype + # Load fonts using PIL font_dir = os.path.join(os.path.dirname(__file__), '..', 'assets', 'fonts') - self.title_face = freetype.Face(os.path.join(font_dir, 'ic8x8u.bdf')) - self.body_face = freetype.Face(os.path.join(font_dir, 'cozette.bdf')) + self.title_font = ImageFont.truetype(os.path.join(font_dir, '5by7.regular.ttf'), 7) + self.body_font = ImageFont.truetype(os.path.join(font_dir, 'dot_digital-7.ttf'), 7) # Load categories and their data self.categories = self.of_the_day_config.get('categories', {}) @@ -165,25 +164,6 @@ class OfTheDayManager: logger.debug("OfTheDayManager update interval reached") self.last_update = current_time - def _draw_bdf_text(self, draw, face, text, x, y, color=(255,255,255)): - """Draw text using a BDF font loaded with freetype.""" - orig_x = x - # Calculate baseline offset for proper text alignment - baseline_offset = face.size.height - face.size.ascender - for char in text: - face.load_char(char) - bitmap = face.glyph.bitmap - # Position text using baseline alignment - for i in range(bitmap.rows): - for j in range(bitmap.width): - byte_index = i * bitmap.pitch + (j // 8) - if byte_index < len(bitmap.buffer): - byte = bitmap.buffer[byte_index] - if byte & (1 << (7 - (j % 8))): - draw.point((x + j, y + baseline_offset + i), fill=color) - x += face.glyph.advance.x >> 6 - return x - orig_x - def draw_item(self, category_name, item): try: title = item.get('title', 'No Title') @@ -192,60 +172,49 @@ class OfTheDayManager: draw = ImageDraw.Draw(self.display_manager.image) matrix_width = self.display_manager.matrix.width matrix_height = self.display_manager.matrix.height - title_face = self.title_face - body_face = self.body_face + title_font = self.title_font + body_font = self.body_font - # Get font heights and set consistent positioning - title_height = title_face.height - body_height = body_face.height + # Get font heights + title_height = title_font.getsize('A')[1] + body_height = body_font.getsize('A')[1] - # --- Draw Title (always at top, ic8x8u.bdf) --- + # --- Draw Title (always at top, 5by7.regular.ttf) --- title_y = 0 # Start at top - self._draw_bdf_text(draw, title_face, title, 1, title_y, color=self.title_color) + draw.text((1, title_y), title, font=title_font, fill=self.title_color) - # Calculate title width and actual height for proper spacing - title_width = 0 - max_title_height = 0 - baseline_offset = title_face.size.height - title_face.size.ascender - for c in title: - title_face.load_char(c) - title_width += title_face.glyph.advance.x - # Track the maximum height including baseline offset - bitmap = title_face.glyph.bitmap - actual_height = baseline_offset + bitmap.rows - if actual_height > max_title_height: - max_title_height = actual_height - title_width = title_width // 64 + # Calculate title width for underline + title_width = title_font.getsize(title)[0] - # Underline below title using actual title height - underline_y = max_title_height + 1 # Just below the actual title + # Underline below title + underline_y = title_height + 1 # Just below the title draw.line([(1, underline_y), (1 + title_width, underline_y)], fill=self.title_color, width=1) - # --- Draw Subtitle or Description (rotating, cozette.bdf) --- + # --- Draw Subtitle or Description (rotating, dot_digital-7.ttf) --- # Start subtitle/description below the title with proper spacing - y_start = max_title_height + 3 # Leave space between title and subtitle + y_start = title_height + 3 # Leave space between title and subtitle available_height = matrix_height - y_start available_width = matrix_width - 2 if self.rotation_state == 0 and subtitle: # Show subtitle - wrapped = self._wrap_text(subtitle, available_width, body_face, max_lines=3, line_height=body_height, max_height=available_height) + wrapped = self._wrap_text(subtitle, available_width, body_font, max_lines=3, line_height=body_height, max_height=available_height) for i, line in enumerate(wrapped): if line.strip(): # Only draw non-empty lines - self._draw_bdf_text(draw, body_face, line, 1, y_start + i * body_height, color=self.subtitle_color) + draw.text((1, y_start + i * body_height), line, font=body_font, fill=self.subtitle_color) elif self.rotation_state == 1 and description: # Show description - wrapped = self._wrap_text(description, available_width, body_face, max_lines=3, line_height=body_height, max_height=available_height) + wrapped = self._wrap_text(description, available_width, body_font, max_lines=3, line_height=body_height, max_height=available_height) for i, line in enumerate(wrapped): if line.strip(): # Only draw non-empty lines - self._draw_bdf_text(draw, body_face, line, 1, y_start + i * body_height, color=self.subtitle_color) + draw.text((1, y_start + i * body_height), line, font=body_font, fill=self.subtitle_color) # else: nothing to show return True except Exception as e: logger.error(f"Error drawing 'of the day' item: {e}", exc_info=True) return False - def _wrap_text(self, text, max_width, face, max_lines=3, line_height=8, max_height=24): + def _wrap_text(self, text, max_width, font, max_lines=3, line_height=8, max_height=24): if not text: return [""] lines = [] @@ -253,11 +222,7 @@ class OfTheDayManager: words = text.split() for word in words: test_line = ' '.join(current_line + [word]) if current_line else word - text_width = 0 - for c in test_line: - face.load_char(c) - text_width += face.glyph.advance.x - text_width = text_width // 64 + text_width = font.getsize(test_line)[0] if text_width <= max_width: current_line.append(word) else: @@ -267,11 +232,7 @@ class OfTheDayManager: else: truncated = word while len(truncated) > 0: - test_width = 0 - for c in (truncated + "..."): - face.load_char(c) - test_width += face.glyph.advance.x - test_width = test_width // 64 + test_width = font.getsize(truncated + "...")[0] if test_width <= max_width: lines.append(truncated + "...") break @@ -285,7 +246,7 @@ class OfTheDayManager: while len(lines) < max_lines: lines.append("") return lines[:max_lines] - + def display(self, force_clear=False): if not self.enabled: return