From a4cefd7c09bbe29a1d4239bf7d345107a1cf8d63 Mon Sep 17 00:00:00 2001 From: Thomas Peterson Date: Sat, 24 Jan 2026 10:42:15 +0100 Subject: [PATCH] Backup --- .../ButtonWidget.cpp.6932614AE5FC71F9.idx | Bin 0 -> 4082 bytes .../ButtonWidget.hpp.551D0D3595AEDB81.idx | Bin 0 -> 784 bytes .../ConfigHandlers.cpp.9A6D389FB90DEEB0.idx | Bin 0 -> 3936 bytes ...leManagerHandlers.cpp.2F53BB33AABE7329.idx | Bin 0 -> 8780 bytes .../clangd/index/Gui.cpp.BDF53DB313293DD9.idx | Bin 3026 -> 3036 bytes .../KnxHandlers.cpp.CB0E869699204D5E.idx | Bin 0 -> 3040 bytes .../LabelWidget.cpp.86E5A1BF3C34B7BC.idx | Bin 0 -> 3486 bytes .../LabelWidget.hpp.C810267C2FCC36BA.idx | Bin 0 -> 716 bytes .../index/LedWidget.cpp.3E101A9B7D9821AD.idx | Bin 0 -> 3506 bytes .../index/LedWidget.hpp.C3DFB6FAB9F8428E.idx | Bin 0 -> 640 bytes ...taticFileHandlers.cpp.7B27CFEA2E9C1EF7.idx | Bin 0 -> 2908 bytes .../StatusHandlers.cpp.1021770D2A2A95F2.idx | Bin 0 -> 3120 bytes .../index/Touch.cpp.EB81940633A1140F.idx | Bin 4008 -> 4240 bytes .../index/WebServer.cpp.552E49883800B71B.idx | Bin 0 -> 10590 bytes .../index/WebServer.hpp.4D1C3D9E0DDB58E5.idx | Bin 0 -> 3386 bytes .../index/Widget.cpp.63DB7B9186B85891.idx | Bin 0 -> 4912 bytes .../index/Widget.hpp.63E5D98A9B23E60F.idx | Bin 0 -> 2236 bytes .../WidgetConfig.cpp.FD56F9F36C29A5DA.idx | Bin 0 -> 8238 bytes .../WidgetConfig.hpp.CAEFE2EEEB2A6996.idx | Bin 4856 -> 7192 bytes .../WidgetFactory.cpp.1026CAEFCA630F22.idx | Bin 0 -> 2676 bytes .../WidgetFactory.hpp.6C7FACD7AA34E439.idx | Bin 0 -> 476 bytes .../WidgetManager.cpp.D8CE609DC911F13E.idx | Bin 22450 -> 34274 bytes .../WidgetManager.hpp.8559171B7B8A010C.idx | Bin 2486 -> 3974 bytes .../index/main.cpp.7C677863E2582AB3.idx | Bin 5876 -> 5988 bytes main/CMakeLists.txt | 9 +- main/WidgetConfig.cpp | 222 +++++++ main/WidgetConfig.hpp | 8 + main/WidgetManager.cpp | 580 +++++------------- main/WidgetManager.hpp | 11 +- main/widgets/ButtonWidget.cpp | 56 ++ main/widgets/ButtonWidget.hpp | 19 + main/widgets/LabelWidget.cpp | 42 ++ main/widgets/LabelWidget.hpp | 15 + main/widgets/LedWidget.cpp | 38 ++ main/widgets/LedWidget.hpp | 14 + main/widgets/Widget.cpp | 96 +++ main/widgets/Widget.hpp | 55 ++ main/widgets/WidgetFactory.cpp | 19 + main/widgets/WidgetFactory.hpp | 11 + 39 files changed, 754 insertions(+), 441 deletions(-) create mode 100644 .cache/clangd/index/ButtonWidget.cpp.6932614AE5FC71F9.idx create mode 100644 .cache/clangd/index/ButtonWidget.hpp.551D0D3595AEDB81.idx create mode 100644 .cache/clangd/index/ConfigHandlers.cpp.9A6D389FB90DEEB0.idx create mode 100644 .cache/clangd/index/FileManagerHandlers.cpp.2F53BB33AABE7329.idx create mode 100644 .cache/clangd/index/KnxHandlers.cpp.CB0E869699204D5E.idx create mode 100644 .cache/clangd/index/LabelWidget.cpp.86E5A1BF3C34B7BC.idx create mode 100644 .cache/clangd/index/LabelWidget.hpp.C810267C2FCC36BA.idx create mode 100644 .cache/clangd/index/LedWidget.cpp.3E101A9B7D9821AD.idx create mode 100644 .cache/clangd/index/LedWidget.hpp.C3DFB6FAB9F8428E.idx create mode 100644 .cache/clangd/index/StaticFileHandlers.cpp.7B27CFEA2E9C1EF7.idx create mode 100644 .cache/clangd/index/StatusHandlers.cpp.1021770D2A2A95F2.idx create mode 100644 .cache/clangd/index/WebServer.cpp.552E49883800B71B.idx create mode 100644 .cache/clangd/index/WebServer.hpp.4D1C3D9E0DDB58E5.idx create mode 100644 .cache/clangd/index/Widget.cpp.63DB7B9186B85891.idx create mode 100644 .cache/clangd/index/Widget.hpp.63E5D98A9B23E60F.idx create mode 100644 .cache/clangd/index/WidgetConfig.cpp.FD56F9F36C29A5DA.idx create mode 100644 .cache/clangd/index/WidgetFactory.cpp.1026CAEFCA630F22.idx create mode 100644 .cache/clangd/index/WidgetFactory.hpp.6C7FACD7AA34E439.idx create mode 100644 main/WidgetConfig.cpp create mode 100644 main/widgets/ButtonWidget.cpp create mode 100644 main/widgets/ButtonWidget.hpp create mode 100644 main/widgets/LabelWidget.cpp create mode 100644 main/widgets/LabelWidget.hpp create mode 100644 main/widgets/LedWidget.cpp create mode 100644 main/widgets/LedWidget.hpp create mode 100644 main/widgets/Widget.cpp create mode 100644 main/widgets/Widget.hpp create mode 100644 main/widgets/WidgetFactory.cpp create mode 100644 main/widgets/WidgetFactory.hpp diff --git a/.cache/clangd/index/ButtonWidget.cpp.6932614AE5FC71F9.idx b/.cache/clangd/index/ButtonWidget.cpp.6932614AE5FC71F9.idx new file mode 100644 index 0000000000000000000000000000000000000000..92a9d6f1fad90d97e4939d547423c7a5ac5b082a GIT binary patch literal 4082 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/ButtonWidget.hpp.551D0D3595AEDB81.idx b/.cache/clangd/index/ButtonWidget.hpp.551D0D3595AEDB81.idx new file mode 100644 index 0000000000000000000000000000000000000000..7f42f37b9857fb1695c8788fb39a4a09e6501390 GIT binary patch literal 784 zcmWIYbaUfiW?*nm@vO*AElFfyU|AhU{_xYc_g?vKQ@1`N$TVSQ-)jEU4lP6dCA)&o2$ZX( zS9BCP9J#`^czM{0#c$spy(u|&_k6?a$&>TEn7KWVo*xNlh$2*cc01ZZ}|dD9587fP97ncwDJ?j zBWo(Hy9Ah6VbUCY93n7j;}E5tMep3FvokR=FtD+(u?T?)22QX;7};2j9N!+lTeS48 z5EBbbzo3AiEKEN`QEFPTI#4gnkBnSkzroCf`Hhhi>?fEo%uhgJkY8ZJ-)?x%3Qj)Z z%E-gUBEzBt6NY&as2b!om~hLMtvB{*uP9*VVdG%o;DPxR$P?v|Mez7p_<3NigNXu7 z0)+z1B#y5d>aXIbOa|I3C?}`^^D|7Ei3<`akjP=+L2>hi!nd)@Tl*FQ^|C3j>A-vj zGXrQ7D7;`s0mCaN(HLkDo6GhRqv~Q?MwpXeerJFwRVkf6Pvz*lEsU@*WGF65E*1wl Wf*tA-kU8q7{&A~$ERAJkX8-_3$l*`` literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/ConfigHandlers.cpp.9A6D389FB90DEEB0.idx b/.cache/clangd/index/ConfigHandlers.cpp.9A6D389FB90DEEB0.idx new file mode 100644 index 0000000000000000000000000000000000000000..2848ec8b6aa9bf8bc4df521fa4f40972fb50f437 GIT binary patch literal 3936 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/FileManagerHandlers.cpp.2F53BB33AABE7329.idx b/.cache/clangd/index/FileManagerHandlers.cpp.2F53BB33AABE7329.idx new file mode 100644 index 0000000000000000000000000000000000000000..b1e706102f3b50f46458d2fbb65fe65c1160ffb4 GIT binary patch literal 8780 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 MAPaJV{L*IpAAx+PvH$=8 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/Gui.cpp.BDF53DB313293DD9.idx b/.cache/clangd/index/Gui.cpp.BDF53DB313293DD9.idx index 5a2df32cb8ea3f7b0fe11ef91ea8f81e20bb49cf..ec388b8533782585efb826faf41fbe11d32646f1 100644 GIT binary patch literal 3036 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 diff --git a/.cache/clangd/index/KnxHandlers.cpp.CB0E869699204D5E.idx b/.cache/clangd/index/KnxHandlers.cpp.CB0E869699204D5E.idx new file mode 100644 index 0000000000000000000000000000000000000000..f56e8228d061a4b2467078d668b8cb7c6fd99256 GIT binary patch literal 3040 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/LabelWidget.hpp.C810267C2FCC36BA.idx b/.cache/clangd/index/LabelWidget.hpp.C810267C2FCC36BA.idx new file mode 100644 index 0000000000000000000000000000000000000000..7584a4408ef03979e1055a26b12c4e7fdfd1071f GIT binary patch literal 716 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 L3?2f|1z`UJ9AcrF literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/LedWidget.hpp.C3DFB6FAB9F8428E.idx b/.cache/clangd/index/LedWidget.hpp.C3DFB6FAB9F8428E.idx new file mode 100644 index 0000000000000000000000000000000000000000..0b51d37ea5ecad20a08abb589030d2879e6ce2a1 GIT binary patch literal 640 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 diff --git a/.cache/clangd/index/WebServer.cpp.552E49883800B71B.idx b/.cache/clangd/index/WebServer.cpp.552E49883800B71B.idx new file mode 100644 index 0000000000000000000000000000000000000000..3b4fbb5d07a426c0264120d7f86b7bacefea90d2 GIT binary patch literal 10590 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/WebServer.hpp.4D1C3D9E0DDB58E5.idx b/.cache/clangd/index/WebServer.hpp.4D1C3D9E0DDB58E5.idx new file mode 100644 index 0000000000000000000000000000000000000000..1cf60d4ee787f9b31660b7d190e108a5f9739420 GIT binary patch literal 3386 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�a`?4Yev`=(QukZ;82^VeBa1J_etCa!yZ6_S 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/WidgetConfig.cpp.FD56F9F36C29A5DA.idx b/.cache/clangd/index/WidgetConfig.cpp.FD56F9F36C29A5DA.idx new file mode 100644 index 0000000000000000000000000000000000000000..d246069819e4322973519d5f28dad1559fe0394e GIT binary patch literal 8238 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/WidgetConfig.hpp.CAEFE2EEEB2A6996.idx b/.cache/clangd/index/WidgetConfig.hpp.CAEFE2EEEB2A6996.idx index f872fcdb758dd43043f565341f4ab4e653195595..c5d6d71fc66d8205ec25030228cbb425f5a4e536 100644 GIT binary patch literal 7192 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 literal 4856 zcmYjT30PD|5`H`$3^UWbIbaSL1_TCBxe;g>ltT^!ii#i*H25jPa)|=*z7>xZ)czxBZjd-i4 zGB?VY+0tUjTJOVx;Z)i|qrIWugSe;$J zw0BJE@->Ilo1-Jxl37aFYJ{4>7)djhE{CX?orc zUFhQX`Qy$gae&_WIbXqg(5iJ#0SjyY&UJf3)JW*%RH1UYt6fes=S|)W3xXhYecUwqbNmBg&?eoZJzsmTcCq1rb+^}5Q{4Z!3Am*KErd$59rC7zA3TD>HLI`e}r>{m{c2Cs|DN5ooqDTgL(EckI_lLyyygCOw@}JxOtJeC=lu2MmNoxtyj`SWoTFDe)@t8z76x;C-;`U@s21{=q*^x3>6B&y>XsptE#Y zCJsou7o;s|x;J^WMo_}F8YF`o2e!Qvzt%y**~kMS*J`z56h@z?%yY-}4{w!*MwJh% zlf@j^KAyz8azMIa$xn~(j6XS976-$FDkY^R4oHuzy)JF2&7bNlf;Lc3g(u;_ygTyb z4h_%QQ>L$_|=SA zu7U;}D9j3f4s5+PEEv|$924a#u5W_%Jz@O-GQi9M*B`%YDvVoo=`Cl$1nYwp!EPMb zdLs|;lVKTm3-_6p$>LC0Zzpyg2VCzjZ(h@}&~b$<1_GTyG7KD$zW2R0u)3;sl`JL! zo$Q)y;(+w|+MnKNUa;(aXVDwH$0%alI56*4?tR+IRc}mP>aay4=;8MCl3vAu{lJ6Y zo??00e#MQvEe25s4syJ5f;pgrgO3_E#AkVJ)rte5Az59mMh-~#N$bDy!s!`XWicLB zr;rqP4oEN972NoY2JX;{;aD2Q=3*Pt(GD%+{Iaj@*Nc%z7nlqDkv?|SCAcxI<*+RJ zvu3EbxN$(*A|8%zef-Y9WpNnzj@QI%IUv2aT%5RnX!$9w7rwtfbI*M+uiIQ9FPurJzb|D1z z=0?n~1HYApK0rq*BefimKHE8I-k+)4|DzFHp=Q;RTFHT3iok2u(>b$wLhat~Gy;KJ zGfGA+2lfLOerr?iy|yh@Ja%0c27rTb60YZf4&DycGGD=n+P4}yqV>8RowiEouq zZ>_fuD~C{jSAQ9A1NGBE#dQ-U0d*71Of<2qqx+p!U7A|t?ntOYr!e7LCDcXdV!|W| z%`xOyu#Qn;VJD`qsF*0MEL2d{ZlQX4Tf0KFx!PWZic4V$Q(E3l0SHZ$5@qZvgpTMr zA_^Ng$}c!)+KasbWf#m$b1^%VTL&eVSv(7rSuitsMKj7PY{Ik^qeB|ZOi?jPlu|G= z9YvQYpsCww#UWTegqBLBYP?!PD~**_Y(<1t zS*vU)8iZE+SNFy)fKLgInoU1lN1Y{QY4MF<-NR9{2?&oG^8quPe9(-~8_aCtK{NjE zqIx;xysEDPb%Ci{is~X$w-nXIrmhsrq%tjDKcN-o3L7?INKvZNc1uxJZNwCDh=O?7 z1cfz#k^^QoH(_|FCSYds621z&NiefH34e{T!OLT#5t=a_Ftd>e%{US<8H0HU_Xfoc z^bSJDga)_K2zSEg24*%B;nT)(2+V92!cDM!fSJueSPD4) zfSJucXvVPz%xvbthlRrqnAxO*r;D!w%xu2FO;kG{oa?*xk6X~rtdf;<>x)U@ zXaF_IhM%sQOp=p4QS9)p;fUGngQ?=|1Af`ygQ?b)R*z=;)Yp~NhqFJT8NB?^vbd9i Vf4k3J$C&6?Ar{So5YzSN{{biEtg8S3 diff --git a/.cache/clangd/index/WidgetFactory.cpp.1026CAEFCA630F22.idx b/.cache/clangd/index/WidgetFactory.cpp.1026CAEFCA630F22.idx new file mode 100644 index 0000000000000000000000000000000000000000..cca6dac4b95f483f999db9f97f2a544478c5ebab GIT binary patch literal 2676 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 T*tFhp@^e>5!3h8|fyw^^@1R-K literal 22450 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 B#sB~S literal 2486 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 T$B$-Zs|Wvq8qfeh6F~hR_BQCu literal 5876 zcmb_gcRbZ!AHN52aqYeLymn;WGBYzS(U8m{E4eo-B^hN@C>ar=gt9X07a=3rD;Cinlh?~}KJWWJpMAz=f^2@=jl*4hAK#Pwsh>+z1H@q;`TFA7LQj#Ec~*^oYtAo45+S_{!l!n{3bAX z_F}6mCR+BR_0@rM>xb2pZ6cpIk)8cH>w|%IFDqZ?2BFYgyj+R z7*3v3+mxT!Y~u09s9O$5d}6xrp4nteWNP%-*2W7*9R@d*n{lnK6DM0I4MI6Eu92Kp z(fG#;QN7cfpHWv@pL1U602tb>$$<*ptXlq_$QR`mLRZ2o^n6&3=O`s@w0?bhk16{7 z>w4CeR($EtBfsX`wYX#bwFG;owdysFMG~D%9!G9E)+>J3Vxq0k{P2_RVu)Vwjx|FT z;`Had$f0u)F(J)sN`e>hzt~Ks+*BGFWu{seAHM%SKY%fL>t{DgaB>}F(wU-<$XG6# zq8E($yxB>8HnN%UZed4X$~RwQdh_eIq;Lw|Em`+l8@S_K_q{^21%#6d& zD8FZ{NTHWupPxz=&sQq>7S43*P+#K*TE_I30wek@tOJeX6Ytg&TY_5qjiqJFtmDIO z5srWEzWYYh9o^oLTo%gPR%TnA_e#ie=vB9{rq-nSciKBg^3~qCCI=h}Qy6W)X6UOC zUZ#s5pWw3;Js_K@yJX=O^59Oz!+`x-eK|}jv1xg|uK%%}_!QsksubL&SgJobj=~NL z%8Sc&O?}GdmQ(pQ=S~$%xN3zNYHs(?>5%17$-i|P@~zf6&A;4#o?QvZ)a~M z^vu1b(IT~qcy#Q5#kW`CQF~nLm%W%a7kDzDsDKNT1D&@>=jx~N+%eIdr1AR5RK zU4FuFO23<0TrQ3IF`5s?>lr0dv)m{t55~_9w@Xe~8WzrVEt(rj52;YC8LPR6 z?EfxAba|>cm1M8pS6lECr=bl16SFfGoxXm{KO%&)u6q6xn6zKHE4AJw^40KoTuY};!O}~q)`S{6mFLM- zFS^E+7gzZ_CSwMo8nJp2=5{6ODL>tr4jAu}r+y&FK5W3l)1@TpA{A`!WtF_%G?L&s zt~{Yx>sg=uxj38;HfFGXEAqS{!;#R*Y91G1H1jk!tz%>7{_a@7zdQdhukc? zFe^p>(z+?Cb-#-yzn5y|g^Xu{xy<#7ABwyhg|vD^Tg)<6R*w8wTlEnLy(Ixs?2L2o z_^TgNUQ`&{^>>@qv)y@<8=o{2w-P<5E!%TKRs%3+ zycr) zPWaOGBek`QeTT(aa4O7bY!EAl*dmAGk2SKFv^vCI9?Y^$JEblOt)e*i&Uh>yS z`;Fc_u##x9G+j#HwCm($Ul!TRPIA~ikpaC=*4Fi$ufIOna9_iBWzeDk|7$*7jnH-O z1|V#1NXU%oDP~J_b(t!1x9Ijc`uAq(Iy`(5;B_@DR<=Oy1^rM>EDt(mpk6TJ;-X7a zxEb0zd%2ePWXK-nsgo=NsmuEoH(9fC3huMq4RWdE&(#Y%9ucv!wexPt+76$@CO0dI zn(9hovi9T;o*P9nflYjRIXxmZv8)cmCm9brtT3BDlxJ-!<#FI!`?MbQLMp`p6r`1u z@W0)aT3@m{97FGrCen$MUo>=}?Jo>!ntjYQU+~DmJ*H>+=;vo#?cdK#HiZpyA3bba zo-~*K`0Y$(+BeVUf7G&;e$q9rpYtY!`MYZa6snu*YfE2CohUQa2zUxm{lJddj_1!v zx<7ya5cDR?qV4EpS*eEqP`K&2nfd`TLdu)x9h|O@7Ce}##{N)j7;ISj0Wv}g`=Dro zc#Xzs462!AwjVgKI`IA(A%o`QR`HP-uSjO9p+8D&(YB2J02v|W=YDH`O^(b`W~!Dy z6l;t%M?XMDNMSxhJ=fi_UQI{U^xF<6Ehk$)Kt{;W(<~wc)s0TDQoa16M4Mh4(+`jl zQikbGXSZg>7nrF=|4{H~JjoSggcMZJvEzixq!svu0!^mJ8#@3^KM;`?F@otjy1{tj z@v0O9f-9*hIY7KNiMl8|Mu7p4Y|5kM*&tqUdZvUJq=G?kekOh{h<7aHPWoOgXF~Ky z?38eZczPjs%+eS?J0)IekvxN{{=iN}(j$SEkb!)P_$lOX;=|cDVk_o?<>qbFhJ^NqThAx@<7JB+(pW&ILt=KRpGj)4JIixYZgbMyXA9 zzCg7*`?eIN^}>i-L#y74(v*CG%G!}>0A!IU)Rffrz+mBDDw18KQK4ND?GXA91~%j1 zX@P$oD~Sq7u0+wIJg~SVQ5~(mExt2fFcMz+;pxoSR zLCMcjZ?)7CcxXk*|A`kCayF24qU4V+e+@JZ(>zMapP;Gxh);Us`Zr_Ow_a6^&a8H$ zw8aVHEAMAjxg+JkqOr_mV);p&`)((Sl5{93)Z6UCE0~RFzj%h9apGkn;$3 z!b=w+qq`-2UVk&L2A`2p!GsuZ%D8r6ZBq@MYJHF{RYEICL6_LICw4Ea^954!-<&Z# z9#Y77>UUS8)dV5m)>dnWrnA8*N%aM`XjNgzUvj7UVr2W4_%~yOTL+Nx ziJalEMneCVE1)LhPa{6-G3jx@UGNihzi@t!3;mlupxmzTtY^lBBevv4<@I2^@CHHp z2ZzQnLLW%3BDV-EJ++nB?%uwKQOI&-5oH`)J~XG(P0izW0l{T4vXT(5C_{CP9^#Is zOglr}_fleRd_2MzWENzHe6h|uD50RRD+n&iD~g4<|9bPoFA*n`|7I!%qpGof?6fI} zZ{){?#kgat8TIaKf76!rYip6Quxk>e5KBoR3t$wcHl zBomSI5QFhy}>bQz+J{8Ikv_4eML^FC#Wbu)|^H?+>7SeUlND^h{ry6n2!xQ5h4 zT-IV!6@r^{oAX0HEuko1XRfrGiliU8P@o$m5xG#Hh$m?3N6FPyBg>W1%G;eIbhbBe zCab3!2}%khMV>3H5LOK4iu9?9fQkqdVQ|Q0NB+-^U$!S zN679|lTlNE`bnYrc=ULJ}Jo3)}%|*}osNzw?7V@5iwluFLg|Hj^8bfe19y3XZcZgb18^o|q zATg4^KVeKr*CB6b*oCC!htY=_Vb|Ta5#pB1zB);{e0Darz}>9r6=IH`mw)??Q;}*K z_pT_LL2zV;LN|y+$r#Z~2D6AB#64*KcyjiY5mDp0-+Ivej4-87(s!I&F}yyH;C3{2 zOz@q$Xx?no6T1>01!|c}6zxB%8k=o41k82g&Bo$>v>T^Io!f zH`%;{Y~D^b@A=;xkYc@q|BtxmQVH`j&<5JU02l-vpa*n<7oZFDf#;wXkd*fQZ;gk) zryn4R|A0pD7*JEOv2*kA^6?7@3JHsdCW1&GU%%ttC;W}~ni!cHnps#|?z1vK6?8fd zM1vR*3jza9IvqNEQ0|D!QRgV&8XOWDcJ6HWnFxD5eH};jd{79IK>@f8u7ImxznHj$ zF1L+_IqyiaPX{j`D17w0Ea0}#u43GuxfJ#sV?twB;4jzC~Pz>&aDo_DRKsBfV nb>J>|1ZqhU($VaoWyCNsv#@e-a-r!N>Om`b2pRx*0#N@2Zeh9# diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 386a88b..8c22062 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,4 +1,9 @@ -idf_component_register(SRCS "KnxWorker.cpp" "Nvs.cpp" "main.cpp" "Display.cpp" "Touch.cpp" "Gui.cpp" "Wifi.cpp" "LvglIdle.c" "Gui/WifiSetting.cpp" "Gui/EthSetting.cpp" "Hardware/Eth.cpp" "WidgetManager.cpp" "SdCard.cpp" +idf_component_register(SRCS "KnxWorker.cpp" "Nvs.cpp" "main.cpp" "Display.cpp" "Touch.cpp" "Gui.cpp" "Wifi.cpp" "LvglIdle.c" "Gui/WifiSetting.cpp" "Gui/EthSetting.cpp" "Hardware/Eth.cpp" "WidgetManager.cpp" "WidgetConfig.cpp" "SdCard.cpp" + "widgets/Widget.cpp" + "widgets/LabelWidget.cpp" + "widgets/ButtonWidget.cpp" + "widgets/LedWidget.cpp" + "widgets/WidgetFactory.cpp" "webserver/WebServer.cpp" "webserver/StaticFileHandlers.cpp" "webserver/ConfigHandlers.cpp" @@ -7,5 +12,5 @@ idf_component_register(SRCS "KnxWorker.cpp" "Nvs.cpp" "main.cpp" "Display.cpp" " "webserver/FileManagerHandlers.cpp" PRIV_REQUIRES spi_flash esp_driver_ppa esp_lcd usb REQUIRES esp_mm esp_eth esp_driver_ppa esp_timer lvgl knx ethernet_init esp_wifi_remote esp_netif esp_event nvs_flash esp_http_server fatfs sdmmc json tinyusb - INCLUDE_DIRS "webserver" + INCLUDE_DIRS "webserver" "widgets" EMBED_TXTFILES "embedded/filemanager.html") diff --git a/main/WidgetConfig.cpp b/main/WidgetConfig.cpp new file mode 100644 index 0000000..d26f8c9 --- /dev/null +++ b/main/WidgetConfig.cpp @@ -0,0 +1,222 @@ +#include "WidgetConfig.hpp" +#include +#include + +// WidgetConfig implementation +void WidgetConfig::serialize(uint8_t* buf) const { + memset(buf, 0, SERIALIZED_SIZE); + size_t pos = 0; + + buf[pos++] = id; + buf[pos++] = static_cast(type); + buf[pos++] = x & 0xFF; buf[pos++] = (x >> 8) & 0xFF; + buf[pos++] = y & 0xFF; buf[pos++] = (y >> 8) & 0xFF; + buf[pos++] = width & 0xFF; buf[pos++] = (width >> 8) & 0xFF; + buf[pos++] = height & 0xFF; buf[pos++] = (height >> 8) & 0xFF; + buf[pos++] = visible ? 1 : 0; + + buf[pos++] = static_cast(textSource); + memcpy(&buf[pos], text, MAX_TEXT_LEN); pos += MAX_TEXT_LEN; + buf[pos++] = knxAddress & 0xFF; buf[pos++] = (knxAddress >> 8) & 0xFF; + buf[pos++] = fontSize; + + buf[pos++] = textColor.r; buf[pos++] = textColor.g; buf[pos++] = textColor.b; + buf[pos++] = bgColor.r; buf[pos++] = bgColor.g; buf[pos++] = bgColor.b; + buf[pos++] = bgOpacity; + buf[pos++] = borderRadius; + + buf[pos++] = shadow.offsetX; + buf[pos++] = shadow.offsetY; + buf[pos++] = shadow.blur; + buf[pos++] = shadow.spread; + buf[pos++] = shadow.color.r; buf[pos++] = shadow.color.g; buf[pos++] = shadow.color.b; + buf[pos++] = shadow.enabled ? 1 : 0; + + buf[pos++] = isToggle ? 1 : 0; + buf[pos++] = knxAddressWrite & 0xFF; buf[pos++] = (knxAddressWrite >> 8) & 0xFF; + buf[pos++] = static_cast(action); + buf[pos++] = targetScreen; +} + +void WidgetConfig::deserialize(const uint8_t* buf) { + size_t pos = 0; + + id = buf[pos++]; + type = static_cast(buf[pos++]); + x = buf[pos] | (buf[pos+1] << 8); pos += 2; + y = buf[pos] | (buf[pos+1] << 8); pos += 2; + width = buf[pos] | (buf[pos+1] << 8); pos += 2; + height = buf[pos] | (buf[pos+1] << 8); pos += 2; + visible = buf[pos++] != 0; + + textSource = static_cast(buf[pos++]); + memcpy(text, &buf[pos], MAX_TEXT_LEN); pos += MAX_TEXT_LEN; + text[MAX_TEXT_LEN - 1] = '\0'; + knxAddress = buf[pos] | (buf[pos+1] << 8); pos += 2; + fontSize = buf[pos++]; + + textColor.r = buf[pos++]; textColor.g = buf[pos++]; textColor.b = buf[pos++]; + bgColor.r = buf[pos++]; bgColor.g = buf[pos++]; bgColor.b = buf[pos++]; + bgOpacity = buf[pos++]; + borderRadius = buf[pos++]; + + shadow.offsetX = static_cast(buf[pos++]); + shadow.offsetY = static_cast(buf[pos++]); + shadow.blur = buf[pos++]; + shadow.spread = buf[pos++]; + shadow.color.r = buf[pos++]; shadow.color.g = buf[pos++]; shadow.color.b = buf[pos++]; + shadow.enabled = buf[pos++] != 0; + + isToggle = buf[pos++] != 0; + knxAddressWrite = buf[pos] | (buf[pos+1] << 8); + pos += 2; + action = static_cast(buf[pos++]); + targetScreen = buf[pos++]; +} + +WidgetConfig WidgetConfig::createLabel(uint8_t id, int16_t x, int16_t y, const char* labelText) { + WidgetConfig cfg = {}; + cfg.id = id; + cfg.type = WidgetType::LABEL; + cfg.x = x; + cfg.y = y; + cfg.width = 150; + cfg.height = 40; + cfg.visible = true; + cfg.textSource = TextSource::STATIC; + strncpy(cfg.text, labelText, MAX_TEXT_LEN - 1); + cfg.fontSize = 1; // 18pt + cfg.textColor = {255, 255, 255}; + cfg.bgColor = {0, 0, 0}; + cfg.bgOpacity = 0; + cfg.borderRadius = 0; + cfg.shadow.enabled = false; + return cfg; +} + +WidgetConfig WidgetConfig::createKnxLabel(uint8_t id, int16_t x, int16_t y, + TextSource source, uint16_t knxAddr, const char* format) { + WidgetConfig cfg = createLabel(id, x, y, format); + cfg.textSource = source; + cfg.knxAddress = knxAddr; + return cfg; +} + +WidgetConfig WidgetConfig::createButton(uint8_t id, int16_t x, int16_t y, + const char* labelText, uint16_t knxAddrWrite, bool toggle) { + WidgetConfig cfg = {}; + cfg.id = id; + cfg.type = WidgetType::BUTTON; + cfg.x = x; + cfg.y = y; + cfg.width = 120; + cfg.height = 50; + cfg.visible = true; + cfg.textSource = TextSource::STATIC; + strncpy(cfg.text, labelText, MAX_TEXT_LEN - 1); + cfg.fontSize = 1; + cfg.textColor = {255, 255, 255}; + cfg.bgColor = {33, 150, 243}; // Blue + cfg.bgOpacity = 255; + cfg.borderRadius = 8; + cfg.shadow.enabled = true; + cfg.shadow.offsetX = 2; + cfg.shadow.offsetY = 2; + cfg.shadow.blur = 8; + cfg.shadow.spread = 0; + cfg.shadow.color = {0, 0, 0}; + cfg.isToggle = toggle; + cfg.knxAddressWrite = knxAddrWrite; + cfg.action = ButtonAction::KNX; + cfg.targetScreen = 0; + return cfg; +} + +// ScreenConfig implementation +void ScreenConfig::clear(uint8_t newId, const char* newName) { + id = newId; + mode = ScreenMode::FULLSCREEN; + backgroundColor = {26, 26, 46}; // Dark blue background + widgetCount = 0; + memset(widgets, 0, sizeof(widgets)); + memset(name, 0, sizeof(name)); + if (newName && newName[0] != '\0') { + strncpy(name, newName, sizeof(name) - 1); + } + // Modal defaults + modalX = 0; // 0 = centered + modalY = 0; // 0 = centered + modalWidth = 0; // 0 = auto + modalHeight = 0; // 0 = auto + modalBorderRadius = 12; + modalDimBackground = true; +} + +int ScreenConfig::addWidget(const WidgetConfig& widget) { + if (widgetCount >= MAX_WIDGETS) return -1; + + // Find next free ID + uint8_t newId = 0; + for (uint8_t i = 0; i < widgetCount; i++) { + if (widgets[i].id >= newId) newId = widgets[i].id + 1; + } + + widgets[widgetCount] = widget; + widgets[widgetCount].id = newId; + widgetCount++; + return newId; +} + +bool ScreenConfig::removeWidget(uint8_t id) { + for (uint8_t i = 0; i < widgetCount; i++) { + if (widgets[i].id == id) { + // Shift remaining widgets + for (uint8_t j = i; j < widgetCount - 1; j++) { + widgets[j] = widgets[j + 1]; + } + widgetCount--; + return true; + } + } + return false; +} + +WidgetConfig* ScreenConfig::findWidget(uint8_t id) { + for (uint8_t i = 0; i < widgetCount; i++) { + if (widgets[i].id == id) return &widgets[i]; + } + return nullptr; +} + +const WidgetConfig* ScreenConfig::findWidget(uint8_t id) const { + for (uint8_t i = 0; i < widgetCount; i++) { + if (widgets[i].id == id) return &widgets[i]; + } + return nullptr; +} + +// GuiConfig implementation +void GuiConfig::clear() { + screenCount = 0; + startScreenId = 0; + standbyEnabled = false; + standbyScreenId = 0xFF; + standbyMinutes = 0; + for (size_t i = 0; i < MAX_SCREENS; i++) { + screens[i].clear(static_cast(i), nullptr); + } +} + +ScreenConfig* GuiConfig::findScreen(uint8_t id) { + for (uint8_t i = 0; i < screenCount; i++) { + if (screens[i].id == id) return &screens[i]; + } + return nullptr; +} + +const ScreenConfig* GuiConfig::findScreen(uint8_t id) const { + for (uint8_t i = 0; i < screenCount; i++) { + if (screens[i].id == id) return &screens[i]; + } + return nullptr; +} diff --git a/main/WidgetConfig.hpp b/main/WidgetConfig.hpp index d0987ee..e8b67bd 100644 --- a/main/WidgetConfig.hpp +++ b/main/WidgetConfig.hpp @@ -121,6 +121,14 @@ struct ScreenConfig { uint8_t widgetCount; WidgetConfig widgets[MAX_WIDGETS]; + // Modal-specific properties (only used when mode == MODAL) + int16_t modalX; // Modal position X (0 = centered) + int16_t modalY; // Modal position Y (0 = centered) + int16_t modalWidth; // Modal width (0 = auto from content) + int16_t modalHeight; // Modal height (0 = auto from content) + uint8_t modalBorderRadius; + bool modalDimBackground; // Dim the background behind modal + void clear(uint8_t newId = 0, const char* newName = nullptr); int addWidget(const WidgetConfig& widget); // Returns widget ID or -1 bool removeWidget(uint8_t id); diff --git a/main/WidgetManager.cpp b/main/WidgetManager.cpp index 28871f9..5610379 100644 --- a/main/WidgetManager.cpp +++ b/main/WidgetManager.cpp @@ -1,9 +1,9 @@ #include "WidgetManager.hpp" +#include "widgets/WidgetFactory.hpp" #include "SdCard.hpp" #include "esp_lv_adapter.h" #include "esp_log.h" #include "esp_timer.h" -#include "Gui.hpp" #include "cJSON.h" #include #include @@ -14,226 +14,6 @@ static const char* TAG = "WidgetMgr"; static constexpr uint8_t SCREEN_ID_NONE = 0xFF; -// Button click callback -static void button_click_cb(lv_event_t* e) { - WidgetConfig* cfg = static_cast(lv_event_get_user_data(e)); - if (!cfg) return; - lv_obj_t* target = static_cast(lv_event_get_target(e)); - WidgetManager::instance().handleButtonAction(*cfg, target); -} - -// WidgetConfig implementation -void WidgetConfig::serialize(uint8_t* buf) const { - memset(buf, 0, SERIALIZED_SIZE); - size_t pos = 0; - - buf[pos++] = id; - buf[pos++] = static_cast(type); - buf[pos++] = x & 0xFF; buf[pos++] = (x >> 8) & 0xFF; - buf[pos++] = y & 0xFF; buf[pos++] = (y >> 8) & 0xFF; - buf[pos++] = width & 0xFF; buf[pos++] = (width >> 8) & 0xFF; - buf[pos++] = height & 0xFF; buf[pos++] = (height >> 8) & 0xFF; - buf[pos++] = visible ? 1 : 0; - - buf[pos++] = static_cast(textSource); - memcpy(&buf[pos], text, MAX_TEXT_LEN); pos += MAX_TEXT_LEN; - buf[pos++] = knxAddress & 0xFF; buf[pos++] = (knxAddress >> 8) & 0xFF; - buf[pos++] = fontSize; - - buf[pos++] = textColor.r; buf[pos++] = textColor.g; buf[pos++] = textColor.b; - buf[pos++] = bgColor.r; buf[pos++] = bgColor.g; buf[pos++] = bgColor.b; - buf[pos++] = bgOpacity; - buf[pos++] = borderRadius; - - buf[pos++] = shadow.offsetX; - buf[pos++] = shadow.offsetY; - buf[pos++] = shadow.blur; - buf[pos++] = shadow.spread; - buf[pos++] = shadow.color.r; buf[pos++] = shadow.color.g; buf[pos++] = shadow.color.b; - buf[pos++] = shadow.enabled ? 1 : 0; - - buf[pos++] = isToggle ? 1 : 0; - buf[pos++] = knxAddressWrite & 0xFF; buf[pos++] = (knxAddressWrite >> 8) & 0xFF; - buf[pos++] = static_cast(action); - buf[pos++] = targetScreen; -} - -void WidgetConfig::deserialize(const uint8_t* buf) { - size_t pos = 0; - - id = buf[pos++]; - type = static_cast(buf[pos++]); - x = buf[pos] | (buf[pos+1] << 8); pos += 2; - y = buf[pos] | (buf[pos+1] << 8); pos += 2; - width = buf[pos] | (buf[pos+1] << 8); pos += 2; - height = buf[pos] | (buf[pos+1] << 8); pos += 2; - visible = buf[pos++] != 0; - - textSource = static_cast(buf[pos++]); - memcpy(text, &buf[pos], MAX_TEXT_LEN); pos += MAX_TEXT_LEN; - text[MAX_TEXT_LEN - 1] = '\0'; - knxAddress = buf[pos] | (buf[pos+1] << 8); pos += 2; - fontSize = buf[pos++]; - - textColor.r = buf[pos++]; textColor.g = buf[pos++]; textColor.b = buf[pos++]; - bgColor.r = buf[pos++]; bgColor.g = buf[pos++]; bgColor.b = buf[pos++]; - bgOpacity = buf[pos++]; - borderRadius = buf[pos++]; - - shadow.offsetX = static_cast(buf[pos++]); - shadow.offsetY = static_cast(buf[pos++]); - shadow.blur = buf[pos++]; - shadow.spread = buf[pos++]; - shadow.color.r = buf[pos++]; shadow.color.g = buf[pos++]; shadow.color.b = buf[pos++]; - shadow.enabled = buf[pos++] != 0; - - isToggle = buf[pos++] != 0; - knxAddressWrite = buf[pos] | (buf[pos+1] << 8); - pos += 2; - action = static_cast(buf[pos++]); - targetScreen = buf[pos++]; -} - -WidgetConfig WidgetConfig::createLabel(uint8_t id, int16_t x, int16_t y, const char* labelText) { - WidgetConfig cfg = {}; - cfg.id = id; - cfg.type = WidgetType::LABEL; - cfg.x = x; - cfg.y = y; - cfg.width = 150; - cfg.height = 40; - cfg.visible = true; - cfg.textSource = TextSource::STATIC; - strncpy(cfg.text, labelText, MAX_TEXT_LEN - 1); - cfg.fontSize = 1; // 18pt - cfg.textColor = {255, 255, 255}; - cfg.bgColor = {0, 0, 0}; - cfg.bgOpacity = 0; - cfg.borderRadius = 0; - cfg.shadow.enabled = false; - return cfg; -} - -WidgetConfig WidgetConfig::createKnxLabel(uint8_t id, int16_t x, int16_t y, - TextSource source, uint16_t knxAddr, const char* format) { - WidgetConfig cfg = createLabel(id, x, y, format); - cfg.textSource = source; - cfg.knxAddress = knxAddr; - return cfg; -} - -WidgetConfig WidgetConfig::createButton(uint8_t id, int16_t x, int16_t y, - const char* labelText, uint16_t knxAddrWrite, bool toggle) { - WidgetConfig cfg = {}; - cfg.id = id; - cfg.type = WidgetType::BUTTON; - cfg.x = x; - cfg.y = y; - cfg.width = 120; - cfg.height = 50; - cfg.visible = true; - cfg.textSource = TextSource::STATIC; - strncpy(cfg.text, labelText, MAX_TEXT_LEN - 1); - cfg.fontSize = 1; - cfg.textColor = {255, 255, 255}; - cfg.bgColor = {33, 150, 243}; // Blue - cfg.bgOpacity = 255; - cfg.borderRadius = 8; - cfg.shadow.enabled = true; - cfg.shadow.offsetX = 2; - cfg.shadow.offsetY = 2; - cfg.shadow.blur = 8; - cfg.shadow.spread = 0; - cfg.shadow.color = {0, 0, 0}; - cfg.isToggle = toggle; - cfg.knxAddressWrite = knxAddrWrite; - cfg.action = ButtonAction::KNX; - cfg.targetScreen = 0; - return cfg; -} - -// ScreenConfig implementation -void ScreenConfig::clear(uint8_t newId, const char* newName) { - id = newId; - mode = ScreenMode::FULLSCREEN; - backgroundColor = {26, 26, 46}; // Dark blue background - widgetCount = 0; - memset(widgets, 0, sizeof(widgets)); - memset(name, 0, sizeof(name)); - if (newName && newName[0] != '\0') { - strncpy(name, newName, sizeof(name) - 1); - } -} - -int ScreenConfig::addWidget(const WidgetConfig& widget) { - if (widgetCount >= MAX_WIDGETS) return -1; - - // Find next free ID - uint8_t newId = 0; - for (uint8_t i = 0; i < widgetCount; i++) { - if (widgets[i].id >= newId) newId = widgets[i].id + 1; - } - - widgets[widgetCount] = widget; - widgets[widgetCount].id = newId; - widgetCount++; - return newId; -} - -bool ScreenConfig::removeWidget(uint8_t id) { - for (uint8_t i = 0; i < widgetCount; i++) { - if (widgets[i].id == id) { - // Shift remaining widgets - for (uint8_t j = i; j < widgetCount - 1; j++) { - widgets[j] = widgets[j + 1]; - } - widgetCount--; - return true; - } - } - return false; -} - -WidgetConfig* ScreenConfig::findWidget(uint8_t id) { - for (uint8_t i = 0; i < widgetCount; i++) { - if (widgets[i].id == id) return &widgets[i]; - } - return nullptr; -} - -const WidgetConfig* ScreenConfig::findWidget(uint8_t id) const { - for (uint8_t i = 0; i < widgetCount; i++) { - if (widgets[i].id == id) return &widgets[i]; - } - return nullptr; -} - -// GuiConfig implementation -void GuiConfig::clear() { - screenCount = 0; - startScreenId = 0; - standbyEnabled = false; - standbyScreenId = 0xFF; - standbyMinutes = 0; - for (size_t i = 0; i < MAX_SCREENS; i++) { - screens[i].clear(static_cast(i), nullptr); - } -} - -ScreenConfig* GuiConfig::findScreen(uint8_t id) { - for (uint8_t i = 0; i < screenCount; i++) { - if (screens[i].id == id) return &screens[i]; - } - return nullptr; -} - -const ScreenConfig* GuiConfig::findScreen(uint8_t id) const { - for (uint8_t i = 0; i < screenCount; i++) { - if (screens[i].id == id) return &screens[i]; - } - return nullptr; -} - // WidgetManager implementation WidgetManager& WidgetManager::instance() { static WidgetManager inst; @@ -241,7 +21,7 @@ WidgetManager& WidgetManager::instance() { } WidgetManager::WidgetManager() { - widgetObjects_.fill(nullptr); + // widgets_ is default-initialized to nullptr createDefaultConfig(); activeScreenId_ = config_.startScreenId; lastActivityUs_ = esp_timer_get_time(); @@ -296,7 +76,6 @@ void WidgetManager::loadFromSdCard() { return; } - // Get file size fseek(f, 0, SEEK_END); long size = ftell(f); fseek(f, 0, SEEK_SET); @@ -307,7 +86,6 @@ void WidgetManager::loadFromSdCard() { return; } - // Read file content char* json = new char[size + 1]; if (!json) { ESP_LOGE(TAG, "Failed to allocate memory for config"); @@ -319,7 +97,6 @@ void WidgetManager::loadFromSdCard() { fclose(f); json[read] = '\0'; - // Parse JSON using cJSON bool success = updateConfigFromJson(json); delete[] json; @@ -336,7 +113,6 @@ void WidgetManager::saveToSdCard() { return; } - // Generate JSON using cJSON char* json = new char[32768]; if (!json) { ESP_LOGE(TAG, "Failed to allocate memory for JSON"); @@ -345,7 +121,6 @@ void WidgetManager::saveToSdCard() { getConfigJson(json, 32768); - // Write to file FILE* f = fopen(CONFIG_FILE, "w"); if (!f) { ESP_LOGE(TAG, "Failed to open config file for writing"); @@ -417,10 +192,11 @@ void WidgetManager::applyScreen(uint8_t screenId) { closeModal(); } + // First destroy C++ widgets (which deletes LVGL objects) + destroyAllWidgets(); + if (esp_lv_adapter_lock(-1) == ESP_OK) { lv_obj_t* root = lv_scr_act(); - lv_obj_clean(root); - widgetObjects_.fill(nullptr); createAllWidgets(*screen, root); esp_lv_adapter_unlock(); } @@ -431,34 +207,111 @@ void WidgetManager::showModalScreen(const ScreenConfig& screen) { closeModal(); } + // Destroy any existing widgets before creating modal widgets + destroyAllWidgets(); + if (esp_lv_adapter_lock(-1) != ESP_OK) return; - lv_obj_t* overlay = lv_obj_create(lv_layer_top()); - lv_obj_set_style_bg_opa(overlay, LV_OPA_COVER, 0); - lv_obj_clear_flag(overlay, LV_OBJ_FLAG_SCROLLABLE); - lv_disp_t* disp = lv_disp_get_default(); - int32_t hor = disp ? lv_disp_get_hor_res(disp) : 1280; - int32_t ver = disp ? lv_disp_get_ver_res(disp) : 800; - lv_obj_set_size(overlay, hor, ver); + int32_t dispWidth = disp ? lv_disp_get_hor_res(disp) : 1280; + int32_t dispHeight = disp ? lv_disp_get_ver_res(disp) : 800; - modalContainer_ = overlay; + // Create semi-transparent background overlay if dimming enabled + lv_obj_t* dimmer = nullptr; + if (screen.modalDimBackground) { + dimmer = lv_obj_create(lv_layer_top()); + lv_obj_remove_style_all(dimmer); + lv_obj_set_size(dimmer, dispWidth, dispHeight); + lv_obj_set_style_bg_color(dimmer, lv_color_black(), 0); + lv_obj_set_style_bg_opa(dimmer, LV_OPA_50, 0); + lv_obj_clear_flag(dimmer, LV_OBJ_FLAG_SCROLLABLE); + } + + // Create modal container + lv_obj_t* modal = lv_obj_create(lv_layer_top()); + lv_obj_clear_flag(modal, LV_OBJ_FLAG_SCROLLABLE); + + // Calculate modal size + int32_t modalWidth = screen.modalWidth; + int32_t modalHeight = screen.modalHeight; + + // Auto-size: calculate from widget bounds if not specified + if (modalWidth <= 0 || modalHeight <= 0) { + int32_t maxX = 0, maxY = 0; + for (uint8_t i = 0; i < screen.widgetCount; i++) { + const WidgetConfig& w = screen.widgets[i]; + if (w.visible) { + int32_t right = w.x + w.width; + int32_t bottom = w.y + w.height; + if (right > maxX) maxX = right; + if (bottom > maxY) maxY = bottom; + } + } + if (modalWidth <= 0) modalWidth = maxX + 40; // Add padding + if (modalHeight <= 0) modalHeight = maxY + 40; + } + + lv_obj_set_size(modal, modalWidth, modalHeight); + + // Position modal (0 = centered) + if (screen.modalX == 0 && screen.modalY == 0) { + lv_obj_center(modal); + } else { + lv_obj_set_pos(modal, screen.modalX, screen.modalY); + } + + // Style modal + lv_obj_set_style_bg_color(modal, lv_color_make( + screen.backgroundColor.r, + screen.backgroundColor.g, + screen.backgroundColor.b), 0); + lv_obj_set_style_bg_opa(modal, LV_OPA_COVER, 0); + lv_obj_set_style_radius(modal, screen.modalBorderRadius, 0); + lv_obj_set_style_border_width(modal, 0, 0); + lv_obj_set_style_pad_all(modal, 0, 0); + + // Add shadow for modal + lv_obj_set_style_shadow_color(modal, lv_color_black(), 0); + lv_obj_set_style_shadow_opa(modal, LV_OPA_30, 0); + lv_obj_set_style_shadow_width(modal, 20, 0); + lv_obj_set_style_shadow_spread(modal, 5, 0); + + modalContainer_ = modal; + modalDimmer_ = dimmer; modalScreenId_ = screen.id; - createAllWidgets(screen, modalContainer_); + + // Create widgets inside modal (not on full screen) + screen_ = modal; + for (uint8_t i = 0; i < screen.widgetCount; i++) { + const WidgetConfig& cfg = screen.widgets[i]; + auto widget = WidgetFactory::create(cfg); + if (widget && cfg.id < MAX_WIDGETS) { + widget->create(modal); + widget->applyStyle(); + widgets_[cfg.id] = std::move(widget); + } + } esp_lv_adapter_unlock(); + ESP_LOGI(TAG, "Modal screen %d opened (%ldx%ld)", screen.id, modalWidth, modalHeight); } void WidgetManager::closeModal() { if (!modalContainer_) return; + // First destroy C++ widgets (which deletes their LVGL objects) + destroyAllWidgets(); + if (esp_lv_adapter_lock(-1) == ESP_OK) { + if (modalDimmer_) { + lv_obj_delete(modalDimmer_); + } lv_obj_delete(modalContainer_); esp_lv_adapter_unlock(); } modalContainer_ = nullptr; + modalDimmer_ = nullptr; modalScreenId_ = SCREEN_ID_NONE; - widgetObjects_.fill(nullptr); } void WidgetManager::showScreen(uint8_t screenId) { @@ -505,7 +358,6 @@ void WidgetManager::handleButtonAction(const WidgetConfig& cfg, lv_obj_t* target ESP_LOGI(TAG, "Button %d clicked, KNX write to %d, state=%d", cfg.id, cfg.knxAddressWrite, state); // TODO: Send KNX telegram - // Gui::knxWorker.writeSwitch(cfg.knxAddressWrite, state); } break; } @@ -586,175 +438,37 @@ void WidgetManager::onUserActivity() { } void WidgetManager::destroyAllWidgets() { - for (auto& obj : widgetObjects_) { - if (obj != nullptr) { - lv_obj_delete(obj); - obj = nullptr; - } + for (auto& widget : widgets_) { + widget.reset(); } } void WidgetManager::createAllWidgets(const ScreenConfig& screen, lv_obj_t* parent) { screen_ = parent; - widgetObjects_.fill(nullptr); - // Set background color lv_obj_set_style_bg_color(parent, lv_color_make( screen.backgroundColor.r, screen.backgroundColor.g, screen.backgroundColor.b), 0); lv_obj_set_style_bg_opa(parent, LV_OPA_COVER, 0); - // Create all widgets for (uint8_t i = 0; i < screen.widgetCount; i++) { const WidgetConfig& cfg = screen.widgets[i]; - lv_obj_t* obj = createWidget(cfg, parent); - if (obj != nullptr && cfg.id < MAX_WIDGETS) { - widgetObjects_[cfg.id] = obj; + auto widget = WidgetFactory::create(cfg); + if (widget && cfg.id < MAX_WIDGETS) { + widget->create(parent); + widget->applyStyle(); + widgets_[cfg.id] = std::move(widget); } } } -lv_obj_t* WidgetManager::createWidget(const WidgetConfig& cfg, lv_obj_t* parent) { - if (!cfg.visible) return nullptr; - - lv_obj_t* obj = nullptr; - - switch (cfg.type) { - case WidgetType::LABEL: { - obj = lv_label_create(parent); - lv_label_set_text(obj, cfg.text); - break; - } - case WidgetType::BUTTON: { - obj = lv_btn_create(parent); - if (cfg.isToggle) { - lv_obj_add_flag(obj, LV_OBJ_FLAG_CHECKABLE); - } - lv_obj_add_event_cb(obj, button_click_cb, LV_EVENT_CLICKED, - const_cast(&cfg)); - - // Create label inside button - lv_obj_t* label = lv_label_create(obj); - lv_label_set_text(label, cfg.text); - lv_obj_set_style_text_color(label, lv_color_make( - cfg.textColor.r, cfg.textColor.g, cfg.textColor.b), 0); - lv_obj_set_style_text_font(label, getFontBySize(cfg.fontSize), 0); - lv_obj_center(label); - break; - } - case WidgetType::LED: { - obj = lv_led_create(parent); - break; - } - } - - if (obj != nullptr) { - lv_obj_set_pos(obj, cfg.x, cfg.y); - if (cfg.width > 0 && cfg.height > 0) { - lv_obj_set_size(obj, cfg.width, cfg.height); - } - if (cfg.type == WidgetType::LED) { - applyLedStyle(obj, cfg); - } else { - applyStyle(obj, cfg); - } - } - - return obj; -} - -void WidgetManager::applyStyle(lv_obj_t* obj, const WidgetConfig& cfg) { - // Text color - lv_obj_set_style_text_color(obj, lv_color_make( - cfg.textColor.r, cfg.textColor.g, cfg.textColor.b), 0); - - // Font - lv_obj_set_style_text_font(obj, getFontBySize(cfg.fontSize), 0); - - // Background (for buttons and labels with bg) - if (cfg.bgOpacity > 0) { - lv_obj_set_style_bg_color(obj, lv_color_make( - cfg.bgColor.r, cfg.bgColor.g, cfg.bgColor.b), 0); - lv_obj_set_style_bg_opa(obj, cfg.bgOpacity, 0); - } - - // Border radius - if (cfg.borderRadius > 0) { - lv_obj_set_style_radius(obj, cfg.borderRadius, 0); - } - - // Shadow - if (cfg.shadow.enabled) { - lv_obj_set_style_shadow_color(obj, lv_color_make( - cfg.shadow.color.r, cfg.shadow.color.g, cfg.shadow.color.b), 0); - lv_obj_set_style_shadow_opa(obj, 180, 0); - lv_obj_set_style_shadow_width(obj, cfg.shadow.blur, 0); - lv_obj_set_style_shadow_spread(obj, cfg.shadow.spread, 0); - lv_obj_set_style_shadow_offset_x(obj, cfg.shadow.offsetX, 0); - lv_obj_set_style_shadow_offset_y(obj, cfg.shadow.offsetY, 0); - } -} - -void WidgetManager::applyLedStyle(lv_obj_t* obj, const WidgetConfig& cfg) { - lv_obj_set_style_radius(obj, LV_RADIUS_CIRCLE, 0); - lv_led_set_color(obj, lv_color_make( - cfg.bgColor.r, cfg.bgColor.g, cfg.bgColor.b)); - lv_led_set_brightness(obj, cfg.bgOpacity); - - if (cfg.shadow.enabled) { - lv_obj_set_style_shadow_color(obj, lv_color_make( - cfg.shadow.color.r, cfg.shadow.color.g, cfg.shadow.color.b), 0); - lv_obj_set_style_shadow_opa(obj, 180, 0); - lv_obj_set_style_shadow_width(obj, cfg.shadow.blur, 0); - lv_obj_set_style_shadow_spread(obj, cfg.shadow.spread, 0); - lv_obj_set_style_shadow_offset_x(obj, cfg.shadow.offsetX, 0); - lv_obj_set_style_shadow_offset_y(obj, cfg.shadow.offsetY, 0); - } -} - -const lv_font_t* WidgetManager::getFontBySize(uint8_t sizeIndex) { - // Font sizes: 0=14, 1=18, 2=22, 3=28, 4=36, 5=48 - // These must be enabled in sdkconfig (CONFIG_LV_FONT_MONTSERRAT_*) - switch (sizeIndex) { - case 0: return &lv_font_montserrat_14; -#if LV_FONT_MONTSERRAT_18 - case 1: return &lv_font_montserrat_18; -#endif -#if LV_FONT_MONTSERRAT_22 - case 2: return &lv_font_montserrat_22; -#endif -#if LV_FONT_MONTSERRAT_28 - case 3: return &lv_font_montserrat_28; -#endif -#if LV_FONT_MONTSERRAT_36 - case 4: return &lv_font_montserrat_36; -#endif -#if LV_FONT_MONTSERRAT_48 - case 5: return &lv_font_montserrat_48; -#endif - default: return &lv_font_montserrat_14; - } -} - void WidgetManager::onKnxValue(uint16_t groupAddr, float value) { if (esp_lv_adapter_lock(100) != ESP_OK) return; - const ScreenConfig* screen = activeScreen(); - if (!screen) { - esp_lv_adapter_unlock(); - return; - } - - for (uint8_t i = 0; i < screen->widgetCount; i++) { - const WidgetConfig& cfg = screen->widgets[i]; - if (cfg.knxAddress == groupAddr && cfg.textSource == TextSource::KNX_DPT_TEMP) { - lv_obj_t* obj = widgetObjects_[cfg.id]; - if (obj != nullptr) { - char buf[32]; - snprintf(buf, sizeof(buf), cfg.text, value); - lv_label_set_text(obj, buf); - } + for (auto& widget : widgets_) { + if (widget && widget->getKnxAddress() == groupAddr) { + widget->onKnxValue(value); } } @@ -764,24 +478,9 @@ void WidgetManager::onKnxValue(uint16_t groupAddr, float value) { void WidgetManager::onKnxSwitch(uint16_t groupAddr, bool value) { if (esp_lv_adapter_lock(100) != ESP_OK) return; - const ScreenConfig* screen = activeScreen(); - if (!screen) { - esp_lv_adapter_unlock(); - return; - } - - for (uint8_t i = 0; i < screen->widgetCount; i++) { - const WidgetConfig& cfg = screen->widgets[i]; - if (cfg.knxAddress == groupAddr && cfg.textSource == TextSource::KNX_DPT_SWITCH) { - lv_obj_t* obj = widgetObjects_[cfg.id]; - if (obj == nullptr) continue; - - if (cfg.type == WidgetType::LABEL) { - lv_label_set_text(obj, value ? "EIN" : "AUS"); - } else if (cfg.type == WidgetType::LED) { - uint8_t brightness = value ? (cfg.bgOpacity > 0 ? cfg.bgOpacity : 255) : 0; - lv_led_set_brightness(obj, brightness); - } + for (auto& widget : widgets_) { + if (widget && widget->getKnxAddress() == groupAddr) { + widget->onKnxSwitch(value); } } @@ -791,25 +490,21 @@ void WidgetManager::onKnxSwitch(uint16_t groupAddr, bool value) { void WidgetManager::onKnxText(uint16_t groupAddr, const char* text) { if (esp_lv_adapter_lock(100) != ESP_OK) return; - const ScreenConfig* screen = activeScreen(); - if (!screen) { - esp_lv_adapter_unlock(); - return; - } - - for (uint8_t i = 0; i < screen->widgetCount; i++) { - const WidgetConfig& cfg = screen->widgets[i]; - if (cfg.knxAddress == groupAddr && cfg.textSource == TextSource::KNX_DPT_TEXT) { - lv_obj_t* obj = widgetObjects_[cfg.id]; - if (obj != nullptr) { - lv_label_set_text(obj, text); - } + for (auto& widget : widgets_) { + if (widget && widget->getKnxAddress() == groupAddr) { + widget->onKnxText(text); } } esp_lv_adapter_unlock(); } +// Helper function to parse hex color string +static uint32_t parseHexColor(const char* colorStr) { + if (!colorStr || colorStr[0] != '#') return 0; + return strtoul(colorStr + 1, nullptr, 16); +} + void WidgetManager::getConfigJson(char* buf, size_t bufSize) const { cJSON* root = cJSON_CreateObject(); if (!root) { @@ -824,7 +519,6 @@ void WidgetManager::getConfigJson(char* buf, size_t bufSize) const { cJSON_AddNumberToObject(standby, "screen", config_.standbyScreenId); cJSON_AddNumberToObject(standby, "minutes", config_.standbyMinutes); - // Add screens array cJSON* screens = cJSON_AddArrayToObject(root, "screens"); for (uint8_t s = 0; s < config_.screenCount; s++) { @@ -840,6 +534,17 @@ void WidgetManager::getConfigJson(char* buf, size_t bufSize) const { screen.backgroundColor.r, screen.backgroundColor.g, screen.backgroundColor.b); cJSON_AddStringToObject(screenJson, "bgColor", bgColorStr); + // Modal-specific properties + if (screen.mode == ScreenMode::MODAL) { + cJSON* modal = cJSON_AddObjectToObject(screenJson, "modal"); + cJSON_AddNumberToObject(modal, "x", screen.modalX); + cJSON_AddNumberToObject(modal, "y", screen.modalY); + cJSON_AddNumberToObject(modal, "w", screen.modalWidth); + cJSON_AddNumberToObject(modal, "h", screen.modalHeight); + cJSON_AddNumberToObject(modal, "radius", screen.modalBorderRadius); + cJSON_AddBoolToObject(modal, "dim", screen.modalDimBackground); + } + cJSON* widgets = cJSON_AddArrayToObject(screenJson, "widgets"); for (uint8_t i = 0; i < screen.widgetCount; i++) { const WidgetConfig& w = screen.widgets[i]; @@ -857,13 +562,11 @@ void WidgetManager::getConfigJson(char* buf, size_t bufSize) const { cJSON_AddNumberToObject(widget, "knxAddr", w.knxAddress); cJSON_AddNumberToObject(widget, "fontSize", w.fontSize); - // Text color char textColorStr[8]; snprintf(textColorStr, sizeof(textColorStr), "#%02X%02X%02X", w.textColor.r, w.textColor.g, w.textColor.b); cJSON_AddStringToObject(widget, "textColor", textColorStr); - // Background color char widgetBgColorStr[8]; snprintf(widgetBgColorStr, sizeof(widgetBgColorStr), "#%02X%02X%02X", w.bgColor.r, w.bgColor.g, w.bgColor.b); @@ -872,7 +575,6 @@ void WidgetManager::getConfigJson(char* buf, size_t bufSize) const { cJSON_AddNumberToObject(widget, "bgOpacity", w.bgOpacity); cJSON_AddNumberToObject(widget, "radius", w.borderRadius); - // Shadow object cJSON* shadow = cJSON_AddObjectToObject(widget, "shadow"); cJSON_AddBoolToObject(shadow, "enabled", w.shadow.enabled); cJSON_AddNumberToObject(shadow, "x", w.shadow.offsetX); @@ -895,7 +597,6 @@ void WidgetManager::getConfigJson(char* buf, size_t bufSize) const { cJSON_AddItemToArray(screens, screenJson); } - // Print to buffer char* jsonStr = cJSON_PrintUnformatted(root); if (jsonStr) { strncpy(buf, jsonStr, bufSize - 1); @@ -908,12 +609,6 @@ void WidgetManager::getConfigJson(char* buf, size_t bufSize) const { cJSON_Delete(root); } -// Helper function to parse hex color string -static uint32_t parseHexColor(const char* colorStr) { - if (!colorStr || colorStr[0] != '#') return 0; - return strtoul(colorStr + 1, nullptr, 16); -} - bool WidgetManager::updateConfigFromJson(const char* json) { cJSON* root = cJSON_Parse(json); if (!root) { @@ -943,7 +638,6 @@ bool WidgetManager::updateConfigFromJson(const char* json) { w.action = ButtonAction::KNX; w.targetScreen = 0; - // Parse basic properties cJSON* id = cJSON_GetObjectItem(widget, "id"); if (cJSON_IsNumber(id)) w.id = id->valueint; @@ -980,7 +674,6 @@ bool WidgetManager::updateConfigFromJson(const char* json) { cJSON* fontSize = cJSON_GetObjectItem(widget, "fontSize"); if (cJSON_IsNumber(fontSize)) w.fontSize = fontSize->valueint; - // Parse colors cJSON* textColor = cJSON_GetObjectItem(widget, "textColor"); if (cJSON_IsString(textColor)) { w.textColor = Color::fromHex(parseHexColor(textColor->valuestring)); @@ -997,7 +690,6 @@ bool WidgetManager::updateConfigFromJson(const char* json) { cJSON* radius = cJSON_GetObjectItem(widget, "radius"); if (cJSON_IsNumber(radius)) w.borderRadius = radius->valueint; - // Parse shadow cJSON* shadow = cJSON_GetObjectItem(widget, "shadow"); if (cJSON_IsObject(shadow)) { cJSON* enabled = cJSON_GetObjectItem(shadow, "enabled"); @@ -1075,6 +767,28 @@ bool WidgetManager::updateConfigFromJson(const char* json) { screen.backgroundColor = Color::fromHex(parseHexColor(bgColor->valuestring)); } + // Parse modal-specific properties + cJSON* modal = cJSON_GetObjectItem(screenJson, "modal"); + if (cJSON_IsObject(modal)) { + cJSON* mx = cJSON_GetObjectItem(modal, "x"); + if (cJSON_IsNumber(mx)) screen.modalX = mx->valueint; + + cJSON* my = cJSON_GetObjectItem(modal, "y"); + if (cJSON_IsNumber(my)) screen.modalY = my->valueint; + + cJSON* mw = cJSON_GetObjectItem(modal, "w"); + if (cJSON_IsNumber(mw)) screen.modalWidth = mw->valueint; + + cJSON* mh = cJSON_GetObjectItem(modal, "h"); + if (cJSON_IsNumber(mh)) screen.modalHeight = mh->valueint; + + cJSON* mr = cJSON_GetObjectItem(modal, "radius"); + if (cJSON_IsNumber(mr)) screen.modalBorderRadius = mr->valueint; + + cJSON* dim = cJSON_GetObjectItem(modal, "dim"); + if (cJSON_IsBool(dim)) screen.modalDimBackground = cJSON_IsTrue(dim); + } + cJSON* widgets = cJSON_GetObjectItem(screenJson, "widgets"); if (!parseWidgets(widgets, screen)) { screen.widgetCount = 0; diff --git a/main/WidgetManager.hpp b/main/WidgetManager.hpp index 944d539..278117b 100644 --- a/main/WidgetManager.hpp +++ b/main/WidgetManager.hpp @@ -1,8 +1,10 @@ #pragma once #include "WidgetConfig.hpp" +#include "widgets/Widget.hpp" #include "lvgl.h" #include +#include class WidgetManager { public: @@ -56,10 +58,6 @@ private: void saveToSdCard(); void destroyAllWidgets(); void createAllWidgets(const ScreenConfig& screen, lv_obj_t* parent); - lv_obj_t* createWidget(const WidgetConfig& cfg, lv_obj_t* parent); - void applyStyle(lv_obj_t* obj, const WidgetConfig& cfg); - void applyLedStyle(lv_obj_t* obj, const WidgetConfig& cfg); - const lv_font_t* getFontBySize(uint8_t sizeIndex); void createDefaultConfig(); void applyScreen(uint8_t screenId); @@ -85,8 +83,9 @@ private: uint8_t navTargetScreen_ = 0xFF; int64_t lastActivityUs_ = 0; - // Runtime widget references (indexed by widget ID) - std::array widgetObjects_; + // Runtime widget instances (indexed by widget ID) + std::array, MAX_WIDGETS> widgets_; lv_obj_t* screen_ = nullptr; lv_obj_t* modalContainer_ = nullptr; + lv_obj_t* modalDimmer_ = nullptr; }; diff --git a/main/widgets/ButtonWidget.cpp b/main/widgets/ButtonWidget.cpp new file mode 100644 index 0000000..a1bbdcb --- /dev/null +++ b/main/widgets/ButtonWidget.cpp @@ -0,0 +1,56 @@ +#include "ButtonWidget.hpp" +#include "../WidgetManager.hpp" + +ButtonWidget::ButtonWidget(const WidgetConfig& config) + : Widget(config) + , label_(nullptr) +{ +} + +void ButtonWidget::clickCallback(lv_event_t* e) { + ButtonWidget* widget = static_cast(lv_event_get_user_data(e)); + if (!widget) return; + lv_obj_t* target = static_cast(lv_event_get_target(e)); + WidgetManager::instance().handleButtonAction(widget->getConfig(), target); +} + +lv_obj_t* ButtonWidget::create(lv_obj_t* parent) { + obj_ = lv_btn_create(parent); + + if (config_.isToggle) { + lv_obj_add_flag(obj_, LV_OBJ_FLAG_CHECKABLE); + } + + lv_obj_add_event_cb(obj_, clickCallback, LV_EVENT_CLICKED, this); + + // Create label inside button + label_ = lv_label_create(obj_); + lv_label_set_text(label_, config_.text); + lv_obj_center(label_); + + lv_obj_set_pos(obj_, config_.x, config_.y); + if (config_.width > 0 && config_.height > 0) { + lv_obj_set_size(obj_, config_.width, config_.height); + } + + return obj_; +} + +void ButtonWidget::applyStyle() { + if (obj_ == nullptr) return; + + // Apply common style to button + applyCommonStyle(); + + // Apply text style to label + if (label_ != nullptr) { + lv_obj_set_style_text_color(label_, lv_color_make( + config_.textColor.r, config_.textColor.g, config_.textColor.b), 0); + lv_obj_set_style_text_font(label_, getFontBySize(config_.fontSize), 0); + } +} + +bool ButtonWidget::isChecked() const { + if (obj_ == nullptr) return false; + return (lv_obj_get_state(obj_) & LV_STATE_CHECKED) != 0; +} diff --git a/main/widgets/ButtonWidget.hpp b/main/widgets/ButtonWidget.hpp new file mode 100644 index 0000000..638a444 --- /dev/null +++ b/main/widgets/ButtonWidget.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "Widget.hpp" + +class ButtonWidget : public Widget { +public: + explicit ButtonWidget(const WidgetConfig& config); + + lv_obj_t* create(lv_obj_t* parent) override; + void applyStyle() override; + + // Check if button is in checked state + bool isChecked() const; + +private: + lv_obj_t* label_ = nullptr; + + static void clickCallback(lv_event_t* e); +}; diff --git a/main/widgets/LabelWidget.cpp b/main/widgets/LabelWidget.cpp new file mode 100644 index 0000000..f749e1d --- /dev/null +++ b/main/widgets/LabelWidget.cpp @@ -0,0 +1,42 @@ +#include "LabelWidget.hpp" +#include + +LabelWidget::LabelWidget(const WidgetConfig& config) + : Widget(config) +{ +} + +lv_obj_t* LabelWidget::create(lv_obj_t* parent) { + obj_ = lv_label_create(parent); + lv_label_set_text(obj_, config_.text); + + lv_obj_set_pos(obj_, config_.x, config_.y); + if (config_.width > 0 && config_.height > 0) { + lv_obj_set_size(obj_, config_.width, config_.height); + } + + return obj_; +} + +void LabelWidget::onKnxValue(float value) { + if (obj_ == nullptr) return; + if (config_.textSource != TextSource::KNX_DPT_TEMP) return; + + char buf[32]; + snprintf(buf, sizeof(buf), config_.text, value); + lv_label_set_text(obj_, buf); +} + +void LabelWidget::onKnxSwitch(bool value) { + if (obj_ == nullptr) return; + if (config_.textSource != TextSource::KNX_DPT_SWITCH) return; + + lv_label_set_text(obj_, value ? "EIN" : "AUS"); +} + +void LabelWidget::onKnxText(const char* text) { + if (obj_ == nullptr) return; + if (config_.textSource != TextSource::KNX_DPT_TEXT) return; + + lv_label_set_text(obj_, text); +} diff --git a/main/widgets/LabelWidget.hpp b/main/widgets/LabelWidget.hpp new file mode 100644 index 0000000..134b750 --- /dev/null +++ b/main/widgets/LabelWidget.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "Widget.hpp" + +class LabelWidget : public Widget { +public: + explicit LabelWidget(const WidgetConfig& config); + + lv_obj_t* create(lv_obj_t* parent) override; + + // KNX updates + void onKnxValue(float value) override; + void onKnxSwitch(bool value) override; + void onKnxText(const char* text) override; +}; diff --git a/main/widgets/LedWidget.cpp b/main/widgets/LedWidget.cpp new file mode 100644 index 0000000..e0729cf --- /dev/null +++ b/main/widgets/LedWidget.cpp @@ -0,0 +1,38 @@ +#include "LedWidget.hpp" + +LedWidget::LedWidget(const WidgetConfig& config) + : Widget(config) +{ +} + +lv_obj_t* LedWidget::create(lv_obj_t* parent) { + obj_ = lv_led_create(parent); + + lv_obj_set_pos(obj_, config_.x, config_.y); + if (config_.width > 0 && config_.height > 0) { + lv_obj_set_size(obj_, config_.width, config_.height); + } + + return obj_; +} + +void LedWidget::applyStyle() { + if (obj_ == nullptr) return; + + // LED-specific styling + lv_obj_set_style_radius(obj_, LV_RADIUS_CIRCLE, 0); + lv_led_set_color(obj_, lv_color_make( + config_.bgColor.r, config_.bgColor.g, config_.bgColor.b)); + lv_led_set_brightness(obj_, config_.bgOpacity); + + // Shadow + applyShadowStyle(); +} + +void LedWidget::onKnxSwitch(bool value) { + if (obj_ == nullptr) return; + if (config_.textSource != TextSource::KNX_DPT_SWITCH) return; + + uint8_t brightness = value ? (config_.bgOpacity > 0 ? config_.bgOpacity : 255) : 0; + lv_led_set_brightness(obj_, brightness); +} diff --git a/main/widgets/LedWidget.hpp b/main/widgets/LedWidget.hpp new file mode 100644 index 0000000..dde5577 --- /dev/null +++ b/main/widgets/LedWidget.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "Widget.hpp" + +class LedWidget : public Widget { +public: + explicit LedWidget(const WidgetConfig& config); + + lv_obj_t* create(lv_obj_t* parent) override; + void applyStyle() override; + + // KNX update (LED responds to switch) + void onKnxSwitch(bool value) override; +}; diff --git a/main/widgets/Widget.cpp b/main/widgets/Widget.cpp new file mode 100644 index 0000000..34c53a8 --- /dev/null +++ b/main/widgets/Widget.cpp @@ -0,0 +1,96 @@ +#include "Widget.hpp" + +Widget::Widget(const WidgetConfig& config) + : config_(config) + , obj_(nullptr) +{ +} + +Widget::~Widget() { + destroy(); +} + +void Widget::destroy() { + if (obj_ != nullptr) { + lv_obj_delete(obj_); + obj_ = nullptr; + } +} + +void Widget::applyStyle() { + if (obj_ == nullptr) return; + applyCommonStyle(); +} + +void Widget::onKnxValue(float /*value*/) { + // Default: do nothing +} + +void Widget::onKnxSwitch(bool /*value*/) { + // Default: do nothing +} + +void Widget::onKnxText(const char* /*text*/) { + // Default: do nothing +} + +void Widget::applyCommonStyle() { + if (obj_ == nullptr) return; + + // Text color + lv_obj_set_style_text_color(obj_, lv_color_make( + config_.textColor.r, config_.textColor.g, config_.textColor.b), 0); + + // Font + lv_obj_set_style_text_font(obj_, getFontBySize(config_.fontSize), 0); + + // Background (for buttons and labels with bg) + if (config_.bgOpacity > 0) { + lv_obj_set_style_bg_color(obj_, lv_color_make( + config_.bgColor.r, config_.bgColor.g, config_.bgColor.b), 0); + lv_obj_set_style_bg_opa(obj_, config_.bgOpacity, 0); + } + + // Border radius + if (config_.borderRadius > 0) { + lv_obj_set_style_radius(obj_, config_.borderRadius, 0); + } + + // Shadow + applyShadowStyle(); +} + +void Widget::applyShadowStyle() { + if (obj_ == nullptr || !config_.shadow.enabled) return; + + lv_obj_set_style_shadow_color(obj_, lv_color_make( + config_.shadow.color.r, config_.shadow.color.g, config_.shadow.color.b), 0); + lv_obj_set_style_shadow_opa(obj_, 180, 0); + lv_obj_set_style_shadow_width(obj_, config_.shadow.blur, 0); + lv_obj_set_style_shadow_spread(obj_, config_.shadow.spread, 0); + lv_obj_set_style_shadow_offset_x(obj_, config_.shadow.offsetX, 0); + lv_obj_set_style_shadow_offset_y(obj_, config_.shadow.offsetY, 0); +} + +const lv_font_t* Widget::getFontBySize(uint8_t sizeIndex) { + // Font sizes: 0=14, 1=18, 2=22, 3=28, 4=36, 5=48 + switch (sizeIndex) { + case 0: return &lv_font_montserrat_14; +#if LV_FONT_MONTSERRAT_18 + case 1: return &lv_font_montserrat_18; +#endif +#if LV_FONT_MONTSERRAT_22 + case 2: return &lv_font_montserrat_22; +#endif +#if LV_FONT_MONTSERRAT_28 + case 3: return &lv_font_montserrat_28; +#endif +#if LV_FONT_MONTSERRAT_36 + case 4: return &lv_font_montserrat_36; +#endif +#if LV_FONT_MONTSERRAT_48 + case 5: return &lv_font_montserrat_48; +#endif + default: return &lv_font_montserrat_14; + } +} diff --git a/main/widgets/Widget.hpp b/main/widgets/Widget.hpp new file mode 100644 index 0000000..d975d0d --- /dev/null +++ b/main/widgets/Widget.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include "../WidgetConfig.hpp" +#include "lvgl.h" + +class Widget { +public: + explicit Widget(const WidgetConfig& config); + virtual ~Widget(); + + // Delete copy/move + Widget(const Widget&) = delete; + Widget& operator=(const Widget&) = delete; + + // Destroy LVGL object + void destroy(); + + // Access to LVGL object + lv_obj_t* getLvglObject() const { return obj_; } + + // Widget ID + uint8_t getId() const { return config_.id; } + + // KNX group address for read binding + uint16_t getKnxAddress() const { return config_.knxAddress; } + + // TextSource for KNX callback filtering + TextSource getTextSource() const { return config_.textSource; } + + // Widget type + WidgetType getType() const { return config_.type; } + + // Config access (for button action handling) + const WidgetConfig& getConfig() const { return config_; } + + // Create LVGL widget on parent - must be implemented by subclasses + virtual lv_obj_t* create(lv_obj_t* parent) = 0; + + // Apply styling after create() - can be overridden + virtual void applyStyle(); + + // KNX callbacks - default implementations do nothing + virtual void onKnxValue(float value); + virtual void onKnxSwitch(bool value); + virtual void onKnxText(const char* text); + +protected: + // Common style helper functions + void applyCommonStyle(); + void applyShadowStyle(); + static const lv_font_t* getFontBySize(uint8_t sizeIndex); + + const WidgetConfig& config_; + lv_obj_t* obj_ = nullptr; +}; diff --git a/main/widgets/WidgetFactory.cpp b/main/widgets/WidgetFactory.cpp new file mode 100644 index 0000000..bef481a --- /dev/null +++ b/main/widgets/WidgetFactory.cpp @@ -0,0 +1,19 @@ +#include "WidgetFactory.hpp" +#include "LabelWidget.hpp" +#include "ButtonWidget.hpp" +#include "LedWidget.hpp" + +std::unique_ptr WidgetFactory::create(const WidgetConfig& config) { + if (!config.visible) return nullptr; + + switch (config.type) { + case WidgetType::LABEL: + return std::make_unique(config); + case WidgetType::BUTTON: + return std::make_unique(config); + case WidgetType::LED: + return std::make_unique(config); + default: + return nullptr; + } +} diff --git a/main/widgets/WidgetFactory.hpp b/main/widgets/WidgetFactory.hpp new file mode 100644 index 0000000..7578a60 --- /dev/null +++ b/main/widgets/WidgetFactory.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "Widget.hpp" +#include "../WidgetConfig.hpp" +#include + +class WidgetFactory { +public: + // Create widget based on WidgetType + static std::unique_ptr create(const WidgetConfig& config); +};