From 33014a53162c018941a7368698d5f964e31d46af Mon Sep 17 00:00:00 2001 From: grayTerminal-sh Date: Tue, 14 Jul 2026 14:34:10 +0200 Subject: [PATCH] refactor(gui): use GtkStack in workspace --- docs/tickets/closed/TICKET-016.md | 289 ++++++++++++++++++++++++++++++ labfy-investigation | Bin 97232 -> 97632 bytes src/widgets/workspace.c | 151 +++++++++------- 3 files changed, 373 insertions(+), 67 deletions(-) create mode 100644 docs/tickets/closed/TICKET-016.md diff --git a/docs/tickets/closed/TICKET-016.md b/docs/tickets/closed/TICKET-016.md new file mode 100644 index 0000000..945b6ae --- /dev/null +++ b/docs/tickets/closed/TICKET-016.md @@ -0,0 +1,289 @@ +# Ticket #016 + +## Titre + +Structurer le `Workspace` avec `GtkStack`. + +--- + +## Objectif + +Remplacer la gestion manuelle de visibilité des pages du `Workspace` par un +`GtkStack`. + +Le `Workspace` doit pouvoir afficher proprement plusieurs pages internes sans +modifier son API publique actuelle. + +Ce ticket prépare l'ajout futur de nouvelles vues : + +- aperçu texte ; +- aperçu image ; +- aperçu PDF ; +- chronologie ; +- fiches d'entités ; +- rapports. + +--- + +## Architecture + +```text +Workspace +└── GtkStack + ├── WelcomePage + └── NodeInformationPage +``` + +Plus tard : + +```text +Workspace +└── GtkStack + ├── WelcomePage + ├── NodeInformationPage + ├── TextPreviewPage + ├── ImagePreviewPage + ├── PdfPreviewPage + └── EntityPage +``` + +Le `Workspace` reste responsable de son affichage interne. + +--- + +## Responsabilités + +Le module `Workspace` doit : + +- créer un `GtkStack` comme widget racine interne ; +- ajouter une page d'accueil ; +- ajouter une page d'informations sur le nœud sélectionné ; +- afficher la page d'accueil lorsqu'aucun nœud n'est sélectionné ; +- afficher la page d'informations lorsqu'un nœud est sélectionné ; +- conserver l'API publique existante. + +--- + +## API publique conservée + +Aucune nouvelle fonction publique n'est requise. + +L'API reste : + +```c +Workspace *workspace_new(void); + +GtkWidget *workspace_get_widget( + const Workspace *workspace +); + +void workspace_set_selected_node( + Workspace *workspace, + const InvestigationNode *node +); + +void workspace_free( + Workspace *workspace +); +``` + +--- + +## Fichiers concernés + +```text +src/widgets/workspace.c +``` + +Éventuellement : + +```text +include/widgets/workspace.h +``` + +uniquement pour mettre à jour la documentation. + +Aucun autre module ne doit être modifié. + +--- + +## Structure interne attendue + +```c +struct Workspace +{ + GtkWidget *root_widget; + GtkWidget *stack; + + GtkWidget *welcome_page; + GtkWidget *welcome_title_label; + GtkWidget *welcome_status_label; + GtkWidget *welcome_instruction_label; + + GtkWidget *node_page; + GtkWidget *node_name_label; + GtkWidget *node_type_label; + GtkWidget *node_parent_label; + GtkWidget *node_children_label; +}; +``` + +Les noms exacts peuvent varier, mais doivent rester explicites. + +--- + +## Pages attendues + +### Page d'accueil + +Nom interne : + +```text +welcome +``` + +Contenu : + +```text +Labfy Investigation + +Aucune enquête ouverte + +Sélectionnez ou créez une enquête +``` + +### Page d'informations + +Nom interne : + +```text +node-information +``` + +Contenu pour un dossier : + +```text +00_BaseDeDonnees + +Type : dossier +Parent : Template +Enfants : 2 +``` + +Contenu pour un fichier : + +```text +Enquete.sqlite + +Type : fichier +Parent : 00_BaseDeDonnees +``` + +--- + +## Comportement attendu + +Lorsque : + +```c +workspace_set_selected_node(workspace, NULL); +``` + +le `GtkStack` doit afficher : + +```text +welcome +``` + +Lorsqu'un nœud valide est transmis : + +```c +workspace_set_selected_node(workspace, node); +``` + +le `GtkStack` doit afficher : + +```text +node-information +``` + +--- + +## Hors périmètre + +Ce ticket ne doit pas : + +- ouvrir un fichier ; +- afficher son contenu ; +- ajouter une barre de navigation ; +- ajouter une animation personnalisée ; +- afficher plusieurs nœuds simultanément ; +- modifier le Core ; +- communiquer avec SQLite. + +--- + +## Contraintes techniques + +- GTK4 uniquement ; +- utiliser `GtkStack` ; +- aucune gestion manuelle de visibilité entre les pages ; +- aucun état global ; +- aucun changement de propriété des nœuds ; +- documentation cohérente ; +- compilation sans warning ; +- aucun `Gtk-CRITICAL`. + +--- + +## Gestion de la propriété + +Le `Workspace` possède uniquement sa structure d'encapsulation. + +Les widgets sont gérés par l'arbre GTK une fois intégrés dans la fenêtre. + +Le nœud reçu reste la propriété du `InvestigationTreeModel`. + +Le `Workspace` ne doit jamais appeler : + +```c +investigation_node_free(node); +``` + +--- + +## Critères d'acceptation + +- [ ] Le projet compile sans warning. +- [ ] `make test` reste entièrement valide. +- [ ] `GtkStack` est utilisé. +- [ ] La page d'accueil apparaît sans sélection. +- [ ] La page d'informations apparaît après sélection. +- [ ] Le passage d'une page à l'autre fonctionne. +- [ ] Aucun appel manuel à `gtk_widget_set_visible()` n'est utilisé pour changer de page. +- [ ] L'API publique de `Workspace` reste stable. +- [ ] Aucun autre module n'est modifié. +- [ ] Aucun `Gtk-CRITICAL`. + +--- + +## Tests manuels + +1. Lancer l'application. +2. Ouvrir une enquête. +3. Vérifier que la page d'accueil est affichée sans sélection. +4. Sélectionner un dossier. +5. Vérifier l'affichage de la page d'informations. +6. Sélectionner un fichier. +7. Vérifier la mise à jour de la même page. +8. Changer d'enquête. +9. Vérifier le retour à la page d'accueil. +10. Lancer `make test`. + +--- + +## Commit attendu + +```text +refactor(gui): use GtkStack in workspace +``` diff --git a/labfy-investigation b/labfy-investigation index 66f0a39213a3b4274062e5d818f50ae7d493abb9..f51fc01cf9ef050e9f61c87ec2fb2905bdb40766 100755 GIT binary patch delta 25893 zcmZ`?2Ygh;^MCv9-sN2{$zAT!djnGFNDD|L^h7~I5dw;U6cG|d1P?_)q)1%#P!U0~ zqtc`a0s?{x2vQV9nkYd~K~a$(KlA_2zIPYM&;R>;*x8+(nVp%Pt?%X7|Ce&|sf+s5zIlO3E3V*=uvzXU zL9G;lJRoPgPwLnR>vHn3ACX%ZrkZe#zKX zdEYEaX*|^s%`(6h%SS1t%t$=U!poIdep2zXB;sKK(8ux|Qz7dsWL&ZOnT>eZZ6aMt z^y~|f?&1eb1?(lEK@VOO70bpVEntKAFy!|M%uHSbOeek#>24vxDCDN7e)f^jx=gKP zE7X|4`K^hRvU$pqyAHtl~qVANStLEj_0(OtU?<8uz0**K$T-HydZwW`aY=!J| z-pN+LS_*7?!7+m`1*TT0vR=shL8u-OY8Bf3ytTv67KrvM?S*jtCE(t&$Fi4&W>bZ% zAtZ~xY4P(EP-h4^BSa^y7p*+B`VmKw!91yI*qvjBjvw&=-|vYHS@Y1P``kY}H1x2$ z?ixCN*tik=3y**GUXO|C_>m*3hE_c|VZ`cv(Lc-aLc%1V?jJpA^zgAGhTb`9^jMv- z$m?7Ex$k=eFEps3trMB84U-JgomMF_NY>OmhXG=g#_712(WC7WXeR6B>bTJeKUsQ| zUy6$@O3_D}I!_w}ss^O}`Y3&Z--v&Lw~4=*W%6n9v4KH4ErF9yX$2aalUBbQUtnMv ztG`RyWeikk6(W7}X{`_iFo17PkL8=vZL3eFA7YvJUPo4;H%ep^uESUIZJDv{M_pGt z@w(ax*Ws(K!%w~rU%mQ3X0&-#;YCx2y3Bh9OVX&ZpgfoIcU@gw=5Q*Hqq0ks2U2-F zl_gQWmCB^&xr^RQmYV zDs$aQXYzES+pa^<{|z6O&TH}8AU?QNJWJ%0TP5XvKz^-m)~|F%`_uiAEuH;CmA!OM z`{#hK^X><#_D-n#i87aOZ8co}<}aSny3AK`rLL}YcFC2}IVH6pQ7fghchyGoCtJ6S zlhBuFLm|HU8a-H89%rj$L)Ti-O&)eFAT*-$<7PgFPI$8KuHHt?9Xm25q)ZaYCf`zIgV zCL{XPUlH0lqKS)_MHBDV;~`_qWxWY2f4tq3tQU8+uagfKad(GUOpCc4O4xh+-VQhA zP5P~_4vr2$<*&&M{wG|rtK@64^;`vm6ZDF2_`wdDaec3^&bqGpbMEQbMgH>-UeU1= zTg_kSn926?tsUdoME-5Z0(<8_AXb;ulE)Tj+Z`I_BsD7Y9>o(_D&JI`*ZB2Ib#=2# z_RN^JN3QaPS;{Zh)d}~Xd-%FG+j38**72{vg7Y>|3Q=o*t#7E7kLc7X?UozrE2w_P zv|6b;BK&c_yHm$9Z$5SZwvTAt+(OoC-JK70O6QgACpAw)656Sy{Qc;$uy&T;b?wgI z6h{5^8}Hw_Sl;;yf4*}k$HXQgv^0s;ytZ?if1p5p+_1SuJniPZK;^$zp8J)LxOt7^ zv&Pp+Yss^_bS{04Q1iSmh?-AIXMd$Nb?kgy-Hd4$$kusE=z6w~QFA^P*qZCH%lXPK z_xaNV>VH&=<~Nm04fwz)hRi%=MI%XyjGD##i;@=IYJb-I;tKib>Q7<6w1QtSQV>l2 zu3!W|`42g@#b5~NBt};!p>OHz1EsUC66XTm>y}n|>qT21hk0iop{j%DNP%sTR6D2S z@@yFUMeV)(y<3K|j@;2T&9&)5WO#sj-#K2~bz*dP=v6vflcb4xlkeSZo09D@`bNq8VzXWdBAP!7zItwfzFfAKzM?MQAbZ=XuZO{A<`u=X*;FnUnuh zn!r}^_-?)0JqBlprY@4C=gvYQJ(NBpGxhLoO`d@|ca=6WWH_Kk?hU z-@*#{OWk8_qiRXial*gLw{~xtc@>*VUD$bz>1%Y{#wX#0k7^B?&{ueTj}*3&x9gF> zy6^!#rm)NWP>-9~S?=ta$-d@K_4NAF&X8boImRW0WNiwxu6;*T{_%ad5`#%p{toim zhp94pH!456s_Q=nI@I1S@Jk2}w6N=YqR$uj$%GHv+XMYpYa)D1+4cB4VQ1~}ANhiw zF^M_XSA0$mn5Qhy(Bv-S!+IsK6a3*`xvgI#6KK+!Q=IYE^Q4vVHX>P!lL!8nXbtIc1JSMj zOVkIb8;P1UAnK3yzB$p5N^L+j4dY!KRu5Ac%~rnXEJ<^e14yynU_$bKf~-a(6yC*O zFKd*;2{{{cEDa7?-w-|&LKt>&=%y-By{mQ&|GO-^xQi%>_<2Ocs?t=*>__7#COm$8 zH)=Ld*_onswd42QLP0ob$t*tJ>+r zDmuN`h2VJoKPb*?vFraMFTaue;59-1(*H-Erjwgt1xC!S+Tr~3igxUAt`2C&DtO6& zCec@q)YWaIX(ZB(Z}P_nr20MqUib4HvPS552Y27<=O^1Z_~`+!WbTHw=Q@d@23Wr@wWyxW7GL}1JmT6zv66=w{1&ed!ObN$c*@NE4iEy;VJE2QeaNM z^;kIFnpghx@$x|l>|Q>8P(iwr8WEAP{<<#OaEP!XI{rDrw+>n;U;Y}~#6T=2T%p^2 zU+EKz*v`!0PY%w&A@2RbcUro6wc&C4Fi*H69_NPO57tuJWij)d9OYD&K&0<<4OrLzk%f;5S_ zXf2`5zX<%Ih(_PbVS9>QA3-}r>#o|i^%~V9*AjA`(h)}mqFG0sgY769@dMpXM=z;I zrvTjv=pd2LuE*!-cKK`15K?rOrlK}b_U(-rb{qAG=7p5nwf{=Jq@Fsno;s)Yi3qiB zzb1TQJ^5ecKux%-c4LH`R8e&wcM;UvU`S^tnfF6Mdk8Cn=``7_xuv+aZ#Y%Q&81#H=`PMd25{Q2W6RGKzH>9fb^X@CtpiV<*gvX~F$c zRZpPzlire;e6f7bnD({ge0HmI?baD5*<)L)OrZFh^i;-CJM+9xiRNe~7Cx$V3Hc@K z&&Px2VNDkVwl>Gi5Gs|duZ_Dww^GuLhQzW@$v{$Wy{_CuV1%8MfD|sAsi}rl6l?H2 zZ=(k7*9Z|MTWi-xB8gmBrkme6(!y4~1s7q^e?g*(Ou*m5jPoV6RsSmFpWT|8^OQ}v z7S-i^N=S+W5+lL{20a5Ywc5}itEe&@r5hqbVuX+=v6?OWl=dcmC?_@uG)%-<83*c5iMvT4lUfd|Jn|Qlx{JnRLXfk^I-S_&(z2muUQr{p9Vey8xr4-Z1FWXdC zHx>Cc+w1D?0(^HzUEMOkYk)K!zT87yYfR6!Mu`VtH91XYwa6aG}zXqtX;UPKMGg~n2IxR8Q?X*34rr)P+kByCKnw>T&>&0hR*(=Q0$x z^7pFKSSdeH9cxP22o0n7FV$%>`ya*}Y2_b!) z--ooE*Gx`MjYb50NaMDX!!=XB*=~~8+M?h`oC>7`gyeht0BFziOGt-u_k+pwvJB}f zyd3Gr{63_3VTbe}U-@7ZSZ{M^y?wVp`A9C-MWO?5q?s(Y8drnc=Io@wd zGP}mBr=;Vh+VjZY!Z#r8!H*&><9{RV#{&-~vw^$~(ph`}(rf%dq|NyA4<*YTJ=%}5{P-y!{z|95IS z+r?9-C9_X>r)lYIAs>PKa{l3M*7@Px~cHz+S^ zP=2pLc}s)xkp|@pTA6<_&phmEgE}+f{`$6)8kF-Jlsh*l-`1dfCqFkYnQi6f`9s+i zK6-vKUWm?~-w~(jPv<9lCR429fnUV4KAvBl-$9-n&u@AvNuC+Edf-zgWA2|VwOSM2 z=+NWSVU`XxtRy|bNAsp~ZfpJ$&u88F9$p}O+w%YNd|B>@xzT<U>A$eoQCG41BbFC??YyyFW#yyd?Ag(NUl zzmS6bb1&qR3qE<_uAD!z(OR_CO+jUvg~(!Gvpd^9hADFHLv_?LWf=W%|1JBje*h^Ru0r)T1*IFK)X$tQz$ z?Ms>dL+vyXGb55lVD2{UkDT!uEtrx+F>EjDb%Vm{p$ zM1HCyk3+TPmYAK8XM7)t?K#M?zQb}U%xtSrYhA^na+{+G&q^L#8VLLVM(Y}uJBUzc zP}s|=k+oOzl}n?u^TA=;nl}>|YZK)Cwrl3iC`5Ikihn%4k(cbV`1z$RgU5lge-uO2 zu~Ei(RPhLNB*M9d{g5je?9h}MUWYZZAsWO6!zN+bQq(GjR>+$q+Z!ZhHZ#x}U2cVf zBd4GxWLR4wpWw3JaDE?P4_$65(S=|d3 zqhvNBFCPG{qesE}gxHU~k>bGkG!l6XG;-!;enwUIaPO;w@FMlTR|jJy+4pKI_B%H% zy9bN&eao8QTb7rXbwg;MTh@X-!;@d@oHz}lc3RIuF}bG9R0Rz`@jIa*LJ1@9;nxz9 zqadB7+Kq6B+5vQU=8_?J*dk{Q-|$-F(f2?~w(k%r11X!KZ;tDzD3zK0zLwJWbirKe3_(p7F8EPx-0?!aW1F9+Q1A8d{2I!TJ?!gFN zlhL>oCHWry@f(G98Z@S?)Fr5J&gFG)_?n8*VHBgoC`N}-j1Hq19Y!%ajAC>og+~YP z`etJ3PS~Qp&vO0nxx<9Sx&s)$d4^hyf|3cd%rh;2qa8_kGz|r=IH8~_xoG^Tt5|L? z(8a9e%iq+7kBZ?#{T!nWpZUnTtNHOa8wDFd@ROFt5M?Vtc8;|RWhcUabFC?qy#)K_ z*;-R}Dzfw42hpnSZ)BfxpP=l^$S$yz5y2c}YwUMY_9&e9wBvqcrIc6D9BngF$(2l! zTcgg>E1?lkL2D}%QY`PPUy}i|VA%@Nz$vNas8~&T=2Z7UwKXE|Qj?JXfbz0iU5NZz z%B#^TgU;&&O}yF@`1K;6pmu_sjUu0@<{}g}iF}gU9Q2!mqL8dKMulZdLI*^bDqL#W znMBIFlvIea?8+XA8Vu2mMAti$&PUb_$h$0Ws5Vq-Ja2h~!HNRWmbX2Ak|xP_!z-4- z?pdVrY08gqXQ0NAi-ga7yX+PVu1F-~Y%nq7^GIb$-V52*-7#Z9BI`5UtH?)YxNlHU z^cij>+$*_f@q~90f;O<*KF%ZBv?${qRM_K8tPKX6(F{LG#;GtzGTsgG%($1@GJX%d z(bxq#sK$rBb^+RRO))=`Uh7chXj^bAgj?4lpW@7q zQm3G#4CEiZ6IYrJVrQfFGl6lYA#b2M!!4Bj4RQL|F{wr`43Pb3&ebtz4XUlN$fvkR ztH)4)u$1L-{acV`#W}T9-5mK8PgB)^Xi;cB^)$D?i3&(5hU)I-IZhy*9g#N>ja-M; zqqDMU+*toXJ|#L=rMUsJYnI32E!SJiXJMOP^loO4XV7%O6K}@+;J89k2w|X{VGJd- z9(aGlD6<)4dm*Tp=<=w3#MjT%nJ_fdNahdu(sz?t8sGMAy!|e6MKC}k)|bT3y;~vw zY3Db;*Sxh1zs2O3T0kHxfoRs95+TyO0!)EMHbVEHdP*dN5yGQ_{QdXhW8Z;+fp|ML z_b3sF=`N~>pL(x7zF$dx--mbLE#IGjmEn!|n+8|HYf&EA{S>&^qtGN)%6tvYv;UZW zzXg)<(DE!qSk%QPha$)GH4LJZANS_2m}0Bz5bwzOAzAnA9wSgt7* zVkYZiiiMbmbTO6oH=yfOw}l3A%_#eDa`?3P6@qcFlvRViV$JN~RjLqV^sq&i3DCK@ z&Zo7|;)WJl>n&8+_k*&HSefLSN_!k%xUxywtgf1%AsUd*quHqImOXVnKf5x;PyHz8 zn&@LXS$t6^I?KA5C$B1$uiAO}DsQ`nqSzuM^^T(lG1UwNKD%b9upK)>B$mlQWSN}0CO$}u z-70noay%=M-Oj9-NNhC9EuS#+x4^?Z+C8peKGf)Y$3h~iCZhe!Nd>6)BWMl8Ehby* z*1TJg*Ct!*HS;tS#AIvz$3sMtjn*k^U&cJgQBrN3W+j<0{-Sa`5hc<$??gb}^UTg&0^XEQj9;7{= zJufp8i;v|V9A}L}&daw5_RA5n~ zxz$meGmUt}-0EtoE)4Uyn%mnW52ed#a&@}FN+C)9g&#%qIJ&}8z&!0}R8@cBJ&%OsA6YmI|Z}5)mvf8C#7+G$%cv`^H{X{_- zCZfSPh8WXCA)Y32D<<(@iG~`KVmk4q>vAw%ezq=wt>9;mQh0r7;+u6VVa?4eNdeP+Pr8Bq#0^f z1VvMgL{o;EH-nL;Bz;0!Ue>>4PVjK!p0=ABaX^SO@;F2x%|LJpBS^WK`j9) zS{t=P$+r5h}ajRn7QUSKow$woUV%(ay<}E_rB94LP zYvzL}m}rw^{>MW^l4}+n8_XEDwJ51B8nnG!qxQ)tnZ<^O7!+-MD%$wuKYZwHJRdK+rKs;Q zG+30^1LdRAks6{l0B?+P#8A2&7)6p(dCI1^=92`&7-GOnF96#HW}tTfV%KEvn6naj zix}>X(dtnYOauA&O>sdQ+4ka`AE;W4Y-dx<$hsBI=JwZ6ftCr#G`bzlbKIyli_xu6 zY|z%pm6e^1yhUuCT)ArJumo2l*9r22WQYgKKn=@LP~V-OSwRe~Oemzdi_}SB4tKL~ zn>~S&kHbn&cHCpgo4+F;OeSnU-eGfQkTza1p7@=>*w-Mj5TcN!tEq6hDH@isOjlP_ z;7kryhN%Vx)zl8oV%ehLGEKw!&T?G6z~VQp%|;0_+=`kUNnQy$Z;Zbw zN_LWOUg-lyo(CddOk63UTM>F5zp}YiyJygzx7_qJFpLC9#-+gcI-8aeh8mNMhrsV^ zY5FjXVRVX@j7|BNkK#v@aBoY~FH}ha8093x9HLl^I_GAKg4krjJmXmicV4h0gfa97 z10d`PLU*OT8KKF+8rm_4&?R;nNY+pIuOE4v3o`v6aIc{>HH+V>?xSPI8Pxf%WvTe?yqrB>tE{A3!&FI@&KaKsVt_ zxA^=jRW`FHV=P_I)0Ka*#n*N!6!WyP_li_%=3XOozWuHn(T){_&J*U^e&;D$De7-f_KLo8iD{Z}rjJi_uSbQ4)XKQ@y21pNd z7ILN&0gWoj(VG`;%W6ZXiO%eaKIBQf7}EgOm_r~`={}<~OQ*b8ENF1JQ!$-4#Tn+Q zZN4B8G-Ga^K&3rybCyK$N0Yldi0Tv;rweZz5nhRzQV372=cN@ajWwRH@rrdNojGL0 z7H#0&XEA5E*xBBijAj}LLeWKGS?+pSyYVTPhow`flO73lzF|gYBhT#CMbzIfe-W0T zuvp3qQ@4UNu?Q( z-vO~;xlPMoh(~_BmY={~I|^{ERJeV9rqUPbCSr17^%h)`SKD*venNz_c&o0xOr`5m6V~q}$%O@+N|-#TNv{eU zRvSE9p`y2v|Fg4c%7fTON%EuVkScdiLAc5n&=-VEGENZyUS?31Jc+SOHOa7AlZ zS9eoZySi#gS?%g-AZ4|yt0RyatzBK6rmS{#HIWFktE}l=Lv0=tg+hfkJD%^XUBS~@p#zNPxQ9GetaM62 z;e?e6T_j^Cw2-`zU)bdg(nVc#uY`Z7O>s{b{jT~B#JI&h9nm`_x45UHJaf9mJ)OwA z+~S^&^0M14?&&D6M!Us5ouG+#i+ehePjHKSI+0Iwi+j4egCsP`EiURrg?3LDy(Pg7 z^|gDt=$%Ov?%F+F^selVsPRh%x~Gfoow*Lmy2L$Q^c(646vPmTe#@f`5xS>~e%o^% z71$QhJzex*H|=N)bWaz}|K44xUCznka!%GR=L~c?7qdHtK1DFl<(zkG-b2W{#J3Myq%f(WsDD#554B?!dx^Quy;d; zdb={07`mpNX(;tzuG`R(%e0(i^kFU&N`BKfu_)cfT&E!<#q=DVj9)$o#{}f=NaN&7AdQy`QJWywL7_zX zWjG^A?uiDHRsJvJq{($KDP7Kk=^3&Y4QI-ephTAZ6Vhz?9`NSKGa)lq ze%KqtSx(-ACL75;p><>VQB*gUuR+HqvJG=izFY=OfvlpoP%>;LM`f`u;c&|)6NP~R%sVWKU(g4wiFkJeIL-^J9DIQ_`t z^dpPYk1S3U`wI|An%#Q0yRo^3TY>S*>1L7+wGw}|>u1DTjPFNXTot&FKiLeZL&FkPM%qPm%{1=g9Xr4Nn=ehv0L&E~^-n=(N-`WHMTyq68|pk^N^unuV*;w<%Set>=`2X3b7@bef*dGUHoS-Hj`JoiXFheMU298_U*j;f%u+>AvO697qt+e zQ%6Ee*)p9diAZb0@gatIG7c2Ln1^7PB{gUaTN_5(1T`f#o3KZ+)3IVgz(hass6M z*ThD92+7^|}e8@px9G&A58q1a$R7=fjehyrW=JOBwhS0G#5yx6otRxD} zu8jy8B~$3`rz=Glt`xo4yd5PH%82GA$5vQ_$(M8q(3PSWSBh7NhIE$f>0CZkgue!D zeyCGY9{SR|g4wBNHjajZiP841iR3Tl{7`fMt0{=d&as3$L==>f?7t`S6NkJ#B~)hp zX`wh|IJ`0sRR+!=j9s;gB|s<=%{oID$zO@ia4CjZLKTMVq_mrX{!A|A#fN>a{jl+K zIbkkpah!`A$?ra#6xFgjLuw=k!A!V74u`jYx+<&#SBIRc$#Yf2dVENLM3sV z!s14W+t1B14SNWx6lceeWHIjP?3ng3I-PYqIDHQ{Bzu zjwA<{VeacAClG~PQyi6^h8>FR{uzT0SE^AvFnY`7*dK-FWl=OC-71SQN(~xm!YIhY z_%pS~t9=mF4ba*|4~mB^dM(^^2RV)M~o@ZhA zN%6S|*8Oa9e@)uc5vgquV8WmS5#qSjI#mmuDt+jL3DR*!q;OUgb;5C`&?wY8fpYO2 znm)%~x?SVp{l0Pr$;c3MFhriX2>uWQVIgzVZYpvU{5%t0CqG7!&Wplolty&``AZr* z&bU#FF~2TmUK)FFS=2tb`(>uPyE2OA;w4PX#iUexTnhG-53qi^KBW8v?p8HPh(mZ;hjpnw6OGI$&`m4YHX?`^=2L#{NaoAKAKGhqTkUs zw=ywblJ6E}OA_|P)Wf3x=tXvX0VFE8AF27;7Zl5uCSAl9iI3968)}wlx94iuXA6VE zD^|@bw%z$HL>zN`dgW9tWk?c*N>VeGryeA4TNN zvfTv1ur4l5H*1Dy3XAT~2E@#pZmK8W#WmIm?g{x;h;ci8V5s5) z!d1?w zmm(@{Je>VZ^!b%wWj_(WNqYxiDJC>EtG&lCX)ggR{cl8D^Z2k+aT&BLaNgu61yp(+ zW3RM7ON8VlAw-Hx<1e3z&!CqwcI~B%=@azX5ZQ7lB2kPR({O(Lly9*1R>mSLVJ);u z4xT=;CC~t^y{EAhM$mEOFDvb69gSnj3i{ki^MNUqmz|Es-%X4?-6BYDu#VnS31U3@ zHV7*Lz1A_)o3Wz_logW{^^K<~aJvdB1-aB#1E8n3z=D3aL#H>>8-q_9|B0qCf17EI z`YiIkz(eo7o;WZ>;wj(91gV|bI$wpEPK-~cQ&(V#chSd+^O9mksnSIstj>3Tj%G=t zczUVBrrOB7RYNpg!ZQ?G^lVtAX)%-)Cgea)0=@5H$rjS{%fa9Z;@?Rc5O~-k7ip8K zYg6WOA>z_Sz|lk~or=QTB{6jwWO$umN;LcuZIC{LEX1L-y%GtY|ALGj2W&B_%IhG6 zj+g;{i0uJjp;ZrG!E^=i8E;iakFO%Kr64o9j4qJM!;u(c(!_ut2{JPwqG@_J#!+gb z7o?J@5-G!uHmWB|vI8Y!qG6iEU8|D|=^cb}n`kgrHGD;^%rqRpLV3e+;>bs0YVIP0 zg&#bV6KwDmNdjb;#yR&B!(~cpkzD`%4rbZDP+NQ(ZYV`AGRy7&Wn`9}jG7qjE&tQV zI>K-HhoAtm@LT?u>84lzHgyBh;WYs^kjzO1v_1yFKmwfM+4w37;))fsF;(DTOZ|>F z`}F4kYGgJZfKvUN{p~2-XsK|mrEjo187$^!lbD}PVtzJ>`Pn4qXOozpO*hWZF<`^| zOg%&M^F)#&=4Vrb`T2I#gy-iu$VcYq)hH+fgHYZ!#!FUdALn3x{uDL1@(2>AK0ni+ z_i69u*ArHspT9vqGC%);g1AA!{7kHH+&-e!=Vuc_#Z1>&hO30_kPX(XxP%~~+oK?F z%mJox63xoy4agf@$Qe?Rh?n86n7CfZTiPLU(%bP0=2mIYid!NU?IL?5r3W}!j3}te zILKu_QE(~qsSqm)e&szX_))-EOi{{-DIltHljrpG-6SpL^4c5;&}@ka+20$6|qs1xI)kur8$JMLM`?^ zs3n)aC}A)JC6!(V8LQ$*+Pg$2#HzocU1M47B9PPHs_R%I(U#ar%F%jkSD5C!-`@%i z{7u-V)RItKG^gsT0%4q(xHKhfGoW*KeASdiC_znQL9*#fOZywqR(+N0OK6HU!6Lcz z^^L~0s~QrW_xVYdOF{^#iJ-0mZ~NUo}9q`)&($ z*?y|p0VPEuS&x$8^ZjQDEsPfSdg#_h#jVXpV4=@|8D$u$D7jjbj^q7Qh{LxVcxBy> znI0I0Dm>jZfK`FsCdG?yNcyo9D$sIbpx{rS?>pF8Q^g34So|3svTTt*3W^d>t&2De zHBSWHbhtQ|L|tmAnI6O$5TC)iNlS5lWD4T{XHiYJ8hc^RFQS$XxAdXuukjQBhMGme zC^}wU)Q?wXQDb1nZ@Qo*!Khcj`MdQ?L5s8gF4SJuiz|YO%c0n*yHSY;$0zZybQYVm zF$(RAbuRgLbO8I-Mjg;5Y+0CeQMa&V$9$9(z9@w+Qs|2d*4#$sT8C-m`OuRd2A#2k zBY(6M{-AbJQ=u8lv~RB@61;P|MT4LwC5890bm~!3S_)*zEf^DqrBAAwNTnolUqOTn#@;R_8F%HSoE_g z_=VV%YbHZ#KI8j;_B}h8sRfWj3Z;N09imm}C`7|vD*`sN`3<o`cP4ps(sWxig`wuPe3(UNnWEQQvQtMnRO$%k_CngtuA|}lBwky&s6fXoH8@S zVp-;M_-F2~BpA$UcO@>=2)_(#=&zQAPQpWA~eL$npiUB z9DJUl#2SW&p7XOdPPLpw>gK4Kp;L_cLO8G0t^O8?)Xqp}EDZad2qYsxi0GZ^lX^tHuny@rP#b zlIS-9hE5nZam4tlp<{;)A2C+ae=z{akt4Kf@%yr%Xh2Xkx(Yu&t1;;kszyw%iU>ec zRn?Q)>lAuJkg3zs58Ym;(!c+pZAk6JI(DyDJp4Wt~_nd&DJWuyNfBo!BMC0x}^pe^ltnuB>TjYgd-SPKHi(Wd*D<ss_fS511R-pFyiy5Z-t^v52=);(nI&bqQoq4Mr5wwtf)M(#T? z(-KwN2KdQ3zOn)SNge-qXeGo2!Y{M1NQh?}s+klgEeV~X>V`Knw3(yUz7M&3pgMdv z6y~O_9aYZ_bwYKwh8JE7^lC+{$T*PdjV{;m4KL*O>iDYAQfjT?6=y0<>u9ZC=m1qW zyb2x{sb)P<9lrJcHf*V0Jvmg=lXW$3uhj6Rp+|bMY*`J4-tLLDerm|v3(lVvD(}Uf zVyi-@dLay+3H?pT1))y8S*%>xDm1V+8xm-E8eWOj%p=>St)T-TV}FLu^+xPiDnfC6 z@CQ0)Lp6QaP`thf{niJe^Fb)J3`EmIZOT|dpy7vmP2pe{dSyZA5mcKadxp@4GS-nT z4*gw*iLrG#^9Me`J3bG5((vzL{wsd_+DpG<9e4vXFVQso1DqVHEuv3%MQuCHA=vAS zXONCBrL!-dCp92V4xK8;0NNscBKr%`z)w2qTmqy>EA6pS_@gMpJZI4L>fd(eVwx;eS_?x=RBmLyz=@W1OLtebI292D%9l z7=is0Y1#14$!BO(vjr%6O{Z$OCt9uJ8@_)!qH&+q01F-HhlT?hC?Zh6?$k>6Yha!L zffulyByIZX1G1UkBkMJ)BcY<(!Fo<3{!=GzxV^K6F5Qk{=GOzTpi&bOzUyhFRd>~^ z8(ut*64mTcjp_xRs^K@LA8S-cH1N9yjGz+yv7Dwyh?-XK2Oi#pabbfAL87Tt}lFM08zZu0B87as=RjW0W% zXuv&3<6bI2V293~C(e!-13LE^jmi+(1~piQ2HI($T!6qh?4GG%aVrJ3lUO+Dc~Ddr z&DE(veaaB!w3yZBE6!vCK@Xj=h`<)8cP zijcsMc@x&&!%i5@k-gEnZ^p9~hR}kE?4<0nh9*v8`R*$)lb$e~A6hwy6}V@{Y3MM# z5V{1kWpccRo*W;_t70uJ>-F;b_|QElyTd^(eQy!0N|U-Z^j0+%)dxeD2pjpYI6}GivsUKa)f&<6&}bAb_5USD=Zr*msQDzuc8YNZnHVMW%cODjcPyf-VfOf_l6Wqbj9 z(6cD4mEw>GQ1ZQTgfdgK0k=t?KhDf7vjY9p=nf#4hm?V=}Ad8pbzeM>I@v{uV zvdJR zkq=bwVPl1^JB92HkMrkebGxV@OY zC3LQ_`&pf+QzcE2%1Y*6?(p+stDn6n^lcFK{vx!_a`;(C(c0aPVs=6JNrhE&g;jZ? zmI8hm^5p*cPCs7;2^Zf3w=Wcy_Sk&hSz?HM*_?TKEAKCnB@j0t>!TdX`_^^;}R!La!BCG z*2^p5PTS1px3+F7 zzGULX?X&v4izQJ^I(U7|5%C2Dv3q>(rk8$_ICQJi)NuKiIO`HoL-9|dhPN8< zP*MM*UW1MA>%17Fwz5mT>}$mbUYE@7=aa6hU_1Hx>pC{u{6l>`+#G<#r>Pas{0xsA zs5nhcy)c}?2Rh+vp3pTnW&G9TysOB+^Fdv&mrXzOm0i1G&VJN2mwmjvEQS4prY4HaGCYrA#J9(oOZCD9kojY>1(%2#l;yldrg~qWjpXCHHw&!!dt%@cU)%jPr}b)WGx@F8mxoTapt0)vh(PuJ zQ1vOTsle=bhT6JRIVFe(G>Qz$#bjWQU5)*QU%q~tf1E)5k7?cc?20*op%>9^ znlMY1OU)%IK4)I#t{!cBUHMk;i!0=#j^Gv5U2G4(V4h$s4S{5r#eb1g+txxsH!-)m z3ARx6u~7AIBzcrC?a{tjRMho$Ot$(YkrKWp1NJ~ubV-l#*#|G@41n$PcfSHg|3D^#s%($qw`5-N6?iJ8WZu(ub#J~Wxl;TuC~WnC{|7^0Sn zqi@O>4At*Z-7mtRf9{@+d zLe=|yeg1J@kY4h5oi-w)l`uNGT@c&GiI__?T%%3C1o2@aCa56p{7pCiNy6VE@O7U9 z5431j0^zR{_-%xbHMbACEt*95#AR3G??yAD-+jf8_DxKmcs1c&YX4H@n;cE=5&m?) zH0-!`_A4koK~_@CT2dC=Nh=^ZY5w0Ke~)`=xI4O&XZH66wtW`&Ysg1cmG|i1)o2lDZ7KO8_>!{9&H%d&+-ccnugES)z=@| zI|NHzXyG^RQ1#p^(HE#T;dqQ`(T`jIm+3fMa4pmF|7CgvsB4*~G-4Wt`cnRfE7XW< zE@r+q!5&7hg{qbB%Oz=vav3QW9)u>}SIBBS!r)W+}vDdzMTQbGXe}{=|^(va61NIwYMP<$n%IYqOcES~&NLG`%SLi?I6YK=}Gc zB>Xl!IxUTyA$&NW_Z#{=Tf~1F+Ck1Z%ZrDN%2{(p;}g9>8y?YBy@8E4VJ_b=tPR`7 zzZ}*rJx{P#M5C_={d=Po4Mx7myALl57pGhs{bQS~=h~C9*BRb2kf5bcAl+JG%k%5EFKS#7o=y zjHi#xmeWu3ZXb}ecZ7&VwbdsHF=QK-PLJk|cFDYEWExw~UmaQ0 zWB^qnru;T-FDk13^*CY0s3<(OeAG(Wcm~_VKr%wEpf5l}L_87unZ5k*s2nzie?RJG zYqd|C72cD4)aX>!md_epFg#Uj3Fcs#y3?*l!~IkTP0Fj0-N-`%Ib4kz$#h{Gm@vFV z)%735O`Fbt9eqdWpQ3?RwfIr=Qgm#*U02E8C}e2_$JUO6AI9n%%?A$h^I%68KRKo{ z{Byi&#E8ZtjV*46+C5p5B<0jr1~oBt?0A?>V0vWtYH%|-3{ z2-Q$4d8eB)y1$KOQEc5V6wuy4OxlJCbD!2R6usj{JcvFO!$(t7dV&W=WQMEadJf1j zJ+K@)F=P%zPsbHqg}i~r-crTr(Rikd)(yd+C`Z&#n2sLZfc67z($PH{(817>Fs(3H zx}PSj7_3*1m?z&Ote8k{a)fB*aDVjfzvZ6N!2Q|#aqeKW;%~XT3huB_{u9+j(c6hF?zen>mQVOMVMWtEqGoD-D~)#fAMP-9a{C7MmmAp2 zqOSj8CvHmv_q+z~Q1m?c{C`Y2dn9g3WdpYw-K=pB)@+M~r&k-en>29eM<2LacZ_*K z1M|;hlioR9{-CwNGYfmNMWN~$^D(Q$MB%p$P7SZYxR!ufr^5{bE}Xkaa^3HuiL`L; zd})RUx*&TX`U+zHg)7>`m`{j1#TrzBXkQ`9^H8p?sErl>MN3?D#crtCCb?GZc5T_c zu#Vlod%7vKWc0R+=5T0f`WFt&>rHXjF2c|$*86SpyK!fALw4cZT4_c)=FSd?K<#N% zgXQf&^c^8xvF2hbh_7ly1ZvvwABaA$6QljFsiTzY2!pPQN+^u4(f1rD52MWXgal&@Z zxOK7q2Z0<=raNGY5GLE!>9%zOM)=`wAm@{5F0Bh_tv`zT&tgT?c(wX()au_59T*=o zR6|JA5IzvK#jDt$S8?VLEY|D@#iQk;@Y2PKsN-*x9EctuiE7%pO^(+dU4FG1F|1&0 zKXSIFTSer@E|Qv1+JMcE*VyD;+9dd4l~}3QV04R9D-Z{wpB)lJctsHJj1hr25Z$N| z*XYFSh)CyfAaHCt#3xVe61Yt5i672e!&b5ONYdur6U)r}XiDv-soP|}`>r88@9rDI zEY;AdFO7RNWcQBx`uWH&+go2h5wQB5`ucT%rvVQFzPb-P2Eg0**Vn6L>y;1R&r0lxu^0@`uyI`CY5eKFun zz)HX;0jC1)23!XCCEx}?E6z1X0fzxz0{jNhtx8h&@F!4!On<;izzKj;0bc`L26!BB z17HG9Bu4>X2fPI6!Ra;;x6!WywgLPTa4_I$oI0li-i9OUqkv<-!u=57Jiya{({UF6 z18^N+npKhpwYpGWUxtkLVtxI1z!Jdw0U!CMzW!Oj!+`GqHu)B=1DpV;;zIn=rTY37 zfUe8+^?d>F{Sk%(VpFz%Ms`MUPkntJm9967>-8LD+u&d6n`noLn`UOqXZG-BGc%aV zd(F(mMd_rOnexcJ+&Mc%IS0lY`3peb$PXcXm|p;KzeXH|g?Jw?xF-{DA$r}DDVz3@ zjA;kZipVPGkTvobz;PQtg!DOn0qHhwnMG*<(j49kX+J&*>1bY!w1B@bD^tFBgdd)j z!5-ijfZEF~_h#bdO##vwycg2hd=k`c7EX^HeX z-Vf;>J_YGCIhibtmmuxL2O@ooPn*+3 z{^>M-Y)%Hdm%lzIQ-1mkZ+1@#zck0lM)9A(^B(ujZ6dEe$6uY7qCA9=xr&dN+XNR^ zbLVE_4*Mw(zy5^3JvUo^u8#b?e4df5<;uKF`SbI<|Li2*d7di&b)NT_m))Z^#$fr? z#?IA@4Fb0VRu2Jv38sI%F%=69h6M(}L=CC~&yFu)Nk;B=Trk|$n6;{bH3vhO@yqi% zW!X2@i-$%ThNl!O?}kgrb2~Qo3vYJtVuL>%dt(!OLxW)=o-C5X6Dt=rD)(qq9^R-t zsZn`;qw-@~xnsNnnpam>xVcgJV59PBK51#D=g&r12fwhChO*`1v1}!u^l&CC<<$>& zWkG)E;Y{zgRILtlsd%oW@ZTQ3PTrQnJ3f*j9}R52@ez{|Ueun6yqdR?FSO@x@j_2f}KMUi!3m8NX9 z8Shk+`1TcvKr-bFl6O03 zIx;mNvD(pKG?C05aT#xO;Mh$jC(l}$#6IPvD>KmcVJmZxpR+QBYF)XqH`?*}%3Y}Y znaA(}J8LQ)h-;dJiD6vK6IQiE zTGmBTh!jgFDnp@!i z)oWThx?mit&HZ;kk*za7vnG#CS^jh&yb=m6d0E?mwnUIOK7*WF>4&yjOPK|h8fu}I z8ODMr8@_@yM#FH@WmpA_+i*SdLBo?s%M5Q}WuKq482LGpJPTxNkHme@XIziO{uuPw zUSb6_%It4}YTLxj1#M7;cL!hnbRae(dRlrX3(*-`(s1 zU~Hwx`|W>N-a^4VfCzti`y($omUG*`+J!Fw<=B}>ne{WZy(us+r+)sFBN2aOM}agAQ9aKGKv6Ts{$ zw9TgK%{6GFtAy|VSJq&{yRXK(OH#jwfM1f`q^oz)DwHfP2;q+)%SCoJLn>rorIv>brt0)sqEUSpvCU zuDRay9BAF#Z-`QrsRc^qX_`e7O%L)ro+}*sR5?|Sc?mn|34=%8i^wZG(?q1Ae2`_S z3qVxvr)8*#uMA9*62K9N<#?QEld4d_V!4S4D7ck6{=;))9ghHIEccP1Jc*BazKngv zS3jTJ!U40D&Vfe>p99mBE`cMI-voZ8tB3YGCZq9Xl;j!wv*(K)G-*tES!+OWMR?}A zq*h{f7{%-`irHZlv%@H6hf&N9qnI5TvDv|IU6&p@ingfhS%Duucbbsc-Ur5SS*Vtw zpyZ-imItiAq8>?kA{zy+(9v0y+%$jGO{}0F_!4*UBkQ#3qhk6{KPPI_=V4?$^Z8%v znups#@nUNWsIpfgyTo=qW#__w57~m0{R8b=YA>bigUCMYp{qi>5x#lE^C@Lt1a_Id zk{BLCw#IQYWxoK!a_3BBrQp9%T_)_yB3Cj=?hcx@Us`jZ!nSf0g4S2m)6{_FXxRp` zz$K}pK-f%q=2B0=wAV!5trj5vI^|`L`V8`0D6b}{cG$dC@T984fZrzaX=-2Sc~j)m z)ixLkJ48N1?F#<4!lIC=v*bHx-Wx_cPlNR%6g#bt)O6v?jyebxnICo z+dIg+t+1@di|tLlBdBd)={1Z$>eV-Kf#j&ilG1rf9}P~9zG}h zVx&_6Gd_z{mgLjWZ9AAa87#6M;hsT09^pPhLD3`Jt#Gg8STVbQG8pzaqQd2Fcl}Xb_a!_8=d06`IxAC@B;8CoiRh3c>7Z-sJ&cTrH6| z5Y5nol3$@tpF1Yi=tBeKCaBKcHUBk`ZS-MJ&@)LrhXRz9y__7F+EE+AdKkv9;JY=uBVUQ?PkHVX+S6sQy%pnK!X$?O|` z=;a4l6(9IYZlBetI^a#UAU-&+kQPE1C}+5xk{w8Ve`1!|4YH${!ldYOa}~)AF_jaB zB8_C(&-c7S$B6T|Zra>~oQGYG1`y+SfXTWD$?rLor9FtDHK_iB zC|yvVM0ThyG&(LsjS)g$C+R}grWjTi9mL*Ct{HFbjp8@%73eFh0g_)q@jWN;K3Sn@ z*&bKc1?>^%{md&VsXpSefLSDn~Bgwy|Y)&z_p1 zF&dCAqFVD+%bvQIn>Pjh)Q@t3=`L`|lxUr0JIK3kDwY)|pSH=@xv?r%Yoy+B_93B~ zQAX;U)QBilD&%;(SLmymsNBWh-qaGui%XlvV)IzJc?vdS>u&^RngwWsUFwucd0sq)9B3Cb3MK#4>3T z%cMyxlP0lD2I9+P?Q5xFTI@El%h2PcW9(jLLm;u!EVu4wmb1X4d9-_cjU|Di?;VSY zX+AL>WiBefysyA(AZZb7ZM&QGKwb;Bwm&R$Q4qn__LrBKBs;BBw!w^fKS4>gbBanb z^PYqnw#w!JNM7&?;DBXF%fr|1dft?wc)c8&J@qL+Zsc8!h}>W3&GAT549#Y-DO zd+(x8iC=64Lww8YZNjwYb2Q7%#o}X~fxIDroKf3?7_SPW&aU~rXn_)8)HO++hJuKb zuG@Xo7D*BN(K~%FfPh7fVym+(e=f<0*y?Vju8hgJ+c>%)52FWCaCNoGe-=fn2(H9r zAnhLWVsLocet^7b9$F}wBKRnonM!c{$8si9A)9?dk_>qRG0NZYH@6hzzku51gcQ1e zloXoCa-x%ViC8(WfK~PxELd&KPjTDUTwIQnY)$ePlDg)erNFb#A;-i^1lJ}$c57be zmY7D??pAMGwDc%(P=<-o;F_t~L4{Nb;x+{F?}>*hloI>$JzMh;F2CNI#U-SPxd|gG7lvQM1%SQL2?~H7bBL zlJ8?^PdnUG)F_o{08M?Dy2MP)$UqTYOAT4eUw)$-?jOE;;}qR2yqO_(#OA!L zEEsQz@XK!|i8)If)C!;yv{^froJ+G-#jK@Rf>B1ZmNu=EiA~$IK0s_VZ&l1&Dxj^j zEj5t5n75YQ&1#XiiesSV56g!rm}rw^`O8a8l6yHF8!VW&QIu3S&07oREk!4N-df%k zI>hG2+NtOw=@Xk9TcMf&Z<{7SgRR82jP#jk9@$#^b3nj6q79F&d6!I-EMmh$0*W?2 z6>WZUWrwT9<9HD(nZLu-VCJ9~#+wU~8qDtiZ#3s&Niv$x0;8Z=ylh8Gn|VTDCJ9Kc zM*!?^FvA=u7rQ1$*ZhshTg7yDPEyaHV4A=m-jNcfne8ac|B}dJX1iJ;BI~ViwQ;Nk z0W}j4TPJ6md=JPLF}oES8?<$D=QVALyj5(S+y!cROoO|*`&06RWJm?dKo!fGFyB*{ zJDddCXP^-Dl&E*dBs{HSb@l~H{u!F;$z;*4b#Re(VMyt7{_Z! ztb{0LP1Gzn-IM{lSgyM#2$IPLQI_YXmZ_$ma29JS3T_j9=fLva{UG8uZ6~$@K?$15 zVH#`Z90W?fBp(8wFVWu$B?sxZ97+O4UJItA#FP-B+Y@>%_wQ`qc{LRI2AY-w!$^T- zd>NRea?`Vfp~@uVH;_+iXWAaaFgnFc#@>9%&eTbTR9!pMcSIxwjB=7;32|%z&GnX5 z!PsP?dB%DucYR|`i(%;dcrcC!qo>Nzn$YB64eh*}&=n4vNVa3#waeFX3gkz~w-X;p zvVM?8qz87eyr2s?2~}?w@4-(dx`We=`r2|thbNjBf?aZ zdU{JB8PA~`yj>la8=))so?S`)1R}O}WMVE|Ei;IJzbmQJgD}k7!O<^H)S8=!c6kdO zuuo>Mj=YEmBKf-0qf~WSbk==hppomcc=O%p>|i5 zy+5&0S85(hZOJqCq$VGO_CUGNGoKh}R!PngymC)o2RcoZv(NzYq$Ew!00QuF3X61~ zQO=rBUMv8&Ra1bU%w|QObo4=M`uuJkK2Z2(Dt;r4=ljwRl*Q73)e9=9DqEXan#00XqUWdtO)7T2mE`=;Xt-W}Kc+!p$&?pO-3`|C&RBujZ>AyF){06QtVs+whDp+Ic`@%~ z&>@MnbWnL@Z_U8ppoJb*n@IcImMzKkw2XSmb49x2Lf*&VxMC45uzY*(=P7$z;$A(p zcWVh<8ClDH)L_FT$XL54_n`cB7z@@Lw7e0oPONum`9-|=og!Q-RlU*1Er~-ZeiUskas%^ z)DjfLC4{rNeI+<0Z%=OwX3TeDXU#worKl|?ds|?%4%0vcM*ej zb@flme!>57evE=RWOzUH!lz-B z=#Jle!g~Tnsmfh6dro@Wl8j={Md6f<-0fFh@}qEC6oSff)aX6y{RlGoN)leQdC!SL zu|k_2@5i>DkSSH@0OS3{OCBpzMg&p#)JBEtC1W?#khzlE54ys1QJ2s!?JufR+|wnz zqP_$*9&t}c{4U8O?&&DcTpn>xC-QEOxTmAM?D2?uI?AgF9&t}6cv3y$o=)V`JmQ{C zHCYi62pEu-*qT0JRgI`x2G9>PoEw} zevz-7Syp3ym6oH=riB=^fHBfVoX5`At8d zgMBwJ_h(QNG$mn(_=YieE@=6tb2%st*Gk2vV`&&tz8jhQE)Yvi)NIQ}NHAogk>;Dgtlztg2W-}L!f626m|9N;{SV5B| zc^7JC@^~~umN`;`d@tN&ln)@U$SUTZNxnZ1J8Ah1xIvY_%*6&x=BWsi@)l^Y$=lH` zyUdX~kjEiSku6y`Ldqdf)8u5ROP9C885#0;RFEmp0zN2DK-02hAMn|7G7M@Wm!s)9 za!XX4D=&dmo-D(xrt&|)lP|AA^#$@{zA(;m@)t0oxjY`^7V;Ayw~!Md)>6(vy9?!s zz!b?rP>UtQ335~(`v4BN9!K7|A2~yBWRO+3!6;kNEJe^N`CE{;euuo_GMt>+I{yG6E+KEAE9BI!`KN(!i^EXbB$Y1zaI4~aFEdQn7il=) z03)t1j0$qb?WFs0G*!-G^xcegCHX2yq!)?w2dYYMn$nX*cA9Gv!Kb{gbg6CwL5e0Q$Wb!kI@)O{vIil=fYRA+!w>jAQ{f1PclasW`WCi zE9pt4;gj3!P12J>Eo)0jI(wH8ZICzaBDS~SYGW=tPuLxlKS9`z7@5YV>=(jzp!`L` z?oZ_{-ft4_30swH)(U~$+Jo%QL(WhIJF*h<`XQg#8Ht+^rKVfdEhs39(ch+tZt|q0 z%tSq=Nur=COE5-Fw+B)|aVv`;W11W|ih^IEy`JfgCbu9`29?!FO?S3{GA|aTC8*Xk z)kzT;W4DUey`LMdgU^GefZGU8aZ_c&owwJ%L0CTzK2wI_92rWy?mC#W z$P{!JlVBSRLsPbw!Y>+io-A!*@PT4W10|PHl@`M+PGle>V8~^(e=t}K^ZA2E+vQZi zY>We1R~@S`dkyUZTOrS=QLH~WCC3N+{L!T3$!NJDC>r|(F`UBKk}QSXdF*=sADEk& zo84tj;9np?;W@`ye%rCszTZM?=4dz75TH{>T07Y~pE!w0tHSvqrg-L9;bY58OtXv@ z9-=-^Y$e1-4wwAv`LSb3_&_RptjMtv&JVT}J>k5-b3Vum@6Cc>YfmX%&x|7>l9ZgQ z;r)yP57qBHgCUAhMR`jXj6p-o0J-QE5}_7L&Qnl}u_XM_0r~XejR2-xx#ioT`9V8rRXzA(ivi*jHq66 zo~QL zKHkQ^J%}+`o=mvo#6cPS7CwX5ANTe3gP8ZTmBt~%;gxxb82AIj*d0}@0YZ^#Rt{Sv z|15NdTQMXPsyIfIvPS}aSXOz}i6nOvZG2Zwdk9n<=Te&T2To*!&qCh`S)nmTXD-P| z5y42s!WNJD?S z*h~Iogr?(XY6~8gTssBbC3N-HbkP;2TE{z{%na{9>>D7b5ruPK<;elY z5E@YYB9=sxRLwFk*$X%+v{=FokBJ)(MnLeF>I6#zqg-WcZ9zt}rz+!ki2vPh13lh>5V0 zd1yBkzX^Vv39pkM&17?J%#4tEDA=FU#Bs(oZ$W%r#e6jP;4<@9aQAAaySvIvv3Ly= zv6zfXZ570x@*d{X?Fq#joPdrH4W1RNX`;A=xHl$TC8Y)tLHn|4Lo}ghU+L-JYv4pREiFuh=xNkWYnM?3!E1=fW?JSkubP=U|RAR)0vC zC_}?CX9arXgyZfTG!OhM?ubWVv6oCe8S{ge3_TTdgO}bXoYv=4 z$VRoEjrqVvJ~$V5LDFa%z2QV!rP>Ta{q%H&0rariVHiW+u^0*Sf<0}YmKq`fIbN;ZU4Z?d(hqyiqX21&jyJ)q=g!gY~LC%X4ZL#PQFX| zMrXJ!#y}tcyqHbvJ^Ir28(REQP@C_FMN-MVm}91)Swv6NMT5F1tEI^x8Zs=KvZD9h znDt37A@Z88%OpMf2I}n}5EnZ_V$`OtdYgvZ$Q$K)dnZb{Nsw>#>Of5b+~Q%izr^Zm z-M~5#z0&*{ofRWbXU)dU^7cZ=YmpVEys(XSElC?O$W6IoE$FL@4U3Bn2dk|)VwT20 zQmxGBTU}slrN+4;F7O!%F=AwRhiL;LGGY03{`w#xDoa_=n|{p1r)#YlZG#(8og|C&gV~m z;_nfAn{)uG#7Bj(w@FUA1&O~*a{m3xBzjL|z;zz4|0EC=M;}ETeH3x@QN+3gf^7c9_(FlV#Ji)r$4)oH+ zo#=0g0bx%=;v$5f`PFeKnCaNTQru*}WX{K!XQ`r~nxlMPU8e-v$hdAc{R_N|1SGWu zKT_9s675r+#mOdgIy(zt?b6+&1c7drOs_>$+IqN#nCJs6A*iWtRO~mlTae1wB)UW8He^-#&isw zHb%A{k82b&$25iibv|j7_Fl#+D={lH;ws1tkgb76XzfjnwK$GWA%EFuPwQ-vOs${~ zt~4K*D)`jTQt{)9hdyf?rgvCpnpJ@rkG>JYT0k#$Ec9;dOd4fHn4-S%_6F|2_hU8w zP8t9|y$2Tj2c0^}G@2)YLEwLEIYFETenwv;j(S&^H zNuxJDEYnJME*}M{F#grijKITc-DFLcZcU}T4MtoOG2kc^N>7^+y(FeS3mwTW2&Ego zOE5@>p$p?sT3Cey58dX`<3w8ws`4BdVI%TiCielbh;>gj_e9=r9HdOTV>+=t4K{<@ z=mx7i4v8@_n`XS_RwOn;Bv61irci34SEQ1u3Mt-I8O?oBlAS0S(+zVazWw980;(yX z8czWjm}wkssXZQ`@=5OU%RZi=t(fKz1K2dNh;+1-mDEO5n#Fi`yLFFkb1VkZU*+hjDQ7Bg2`6#4{La8z(Or$hX zDpQJylr9P($#WQn$Z0I8GkiloQ)KPQNiGOT?%uYK2t(mqav_{c?!MN`F$|+=CaLtp z2jdi#3T6tmlt{+Ak$8frNX{VD2m(1oB;Bc!OJ6-Y5z0pTJ_ozxQ-W|%vt$~)D!sNb zPDkJ4;~ruYYSka$DPv`FEx7M)z#56S!a+)^<5-uzP^=+Ln7WM#KYQq&LB&18PE@ml zh?HSs#`yI0Ls+0kcM|%9*o2MN-{6?uvh^pz5Q)*qmaO^;VMnC88m%vOO~P@!g39of z1p+kgN;+PPR_Xn=qo;%P4j~eacP2LAssVEDTddR-Q;GBr)QCi~z73P!WXTU+t1OMa zmSAPfbmmqq2ur;nLJzB@H#X_wtBo=iq=E?FG(I!viwbtcbmw@%D%}PgJ*@ULrjVOt z{_Q3SL(P?WZraYjmqA@)sJS!`r!Gl4<{>|cQ!oSD2O2d@C%T(p=Z88O2Riz=^LQ$C zrJ?4bu$hiDC-fstnfVfUPuV^Y#ARVKjo;IH5og8gF|f|)#Wmri$!1BangCurII@W6 zGQ}(JY*27`l{B8Yjd*@~y@97v$|N=ZTQu>Q8m6*jT?^Ky;9uwaNsG| z0GP=}QAd`}JW*;Agy-b8j0tb$+&%p+DrHbN-!tWfG20F#hx8t9eK87p^EIx9)=Ft2%d78_w3 zmgOUr$$Z&2{^tH1$!5FGX24(wxR6D>H?r$&Ht2^AMXNm(HA!hJ94y6~E=&*<&4LV` z`D2PVGhTyjgfa|Tg53R6l6iK3YRW?1Z>C&!A>+m0CADu-i1umv$;KcAa-dk%P~?(a z8)jNwn`>}QSNy`};P-V~XE0X9m^E@zX2M*jqAtYU}MPdylc6 zk&agOC0n~SXk(ih8@ctkof!;l(i1x%2ds;L`K}eE1)X)0goY@De87bxmO*a;I3W0MPUYeF!EUv%W0dTc2m;u ziv#wB;(bt2|DjlJRNUZQ3*HR;(`lIxDCrtk&I3wzZtLg(D2!kDT$d z4BKu=&c|0MO0uCRVLPabqE@N{)B%y30xT&qHh^{`N%O7=pF~^EOTkH^fd5eV&Z*#odX?ksjqNm>`r315u%F(%t3kvJ$y7gug#o zY%oUFgjkRrjO+=qA{LBX4zXlUWqYk(V`-ZR>&22I#k~-IrbasSVnuRY`^as*SPzW8 z$fjOw39-Rk zW{q5c7~2>r>BEwHoz!n}V$wGw{1MmhjqtN{e6aG`+7|2hibxIA1!C`pFy+Ow2V^Ft zNb@6mh}`(1gO(+#?U~4BBFC;;V$%I|a^FZ+U)b9C{%Dy_-lyNP#4e;>*71$+xBji; z+e8*XU7+!eA$_(;#`q!|iQM>RbxNFkp2)FFAs>g3XhryuKSSy-jv%Of}SV@>5t z^CFA;VIxu%xd1AnM@fJ72)iq?r$0+(gCl49135L4HGn0{m)b=-4q#&fjgOY}qe`#r zka8j$!N#^k4h_KAIXo=#+W`FD<@w08N;Vd610o+(V(83>uz_HziUbC-qCn&C;99}K zZuH93$W0(y;v0g<;{#b&HYRdrAZr?+uh6}4N8?|XoD+Wp`A144RfCx7Y5Y4DGyQer zk_>FMNqlH$%@MJ+w4;t!=>Ummu?D1J;%_3)jqDkOxg-8ibl{NAT3V{{oYYy*5^LZ- zyj-S6EaN&_2N#H{T!Cy*`~_^Y_@l~MA}tl^0FmAz()l7?CermHJw$1MezryCpAb7? z+zjj5@uzq3Cz@T6rw7Bm1sdokK(9eqY1}x>PHkk+2;fOo<4^Ra>iEWA!at;GeNF?r zH1O}pO+(-qOQdE9D$W-ma6Ps%q`C2Lvd3v$69p)_U*~GPJz1{f8^6VQU6bCgfjSLb z(SSR$U?}P@jBFf=aWx2=LaN`V&%D;Ulcs814+{{PIt+ha`)QF6&|mr?iN-suy&Czb zPHucn^1Vi`*U61bfgKw7Py4CKf?8}$33 z=X8g*1KuMCq=}6bbdPKt0b@o85SXJ&f89Y73+mFf8rOCWoYTOM8n8s3z7g%n#eEP} zEUtARR)@uco)SSWxn3tXes6iVj&J|bZIGaeiYp3NkBhI7=KeWJk|v91O=J3(m)Rl4ANxogbXzkcY5Lx zr&Z)0(74uUV21|IXyB3nTgI?Dbt}7-wKYagb!CZ>F}E`d{VDjZi*9G18n@1v%3d;H zUt)>`r?WbFgEb=0V1=HQu#cV?ERA%V!HPUb=^74C41N(=0JL>miiX~n5_xk5YiGTp zm#?HmenZ(4`*R#I7>snA$-?qcQ{?TLs4VuMF~nf22)hSMPR>M4YfhxYJy`mxA`1u` z{|^!(Z`{M$TQ@&9Zga_=l~$NwjWt#8bNN;WIPW|K~R z%2Y)<%m!C1I8Tk-I~!}=)W{nImPCF9us%tbQFx+5BIWm?hJ_cka%p72eURNQX|tj> zvWJSp0$OoUgv~+mg>G8$vq(1- +#define WORKSPACE_PAGE_WELCOME "welcome" +#define WORKSPACE_PAGE_NODE_INFORMATION "node-information" + /** * @struct Workspace * @brief Représentation interne de la zone de travail. - * - * Cette structure reste privée au module. Les autres fichiers utilisent - * uniquement le type opaque déclaré dans workspace.h. */ struct Workspace { GtkWidget *root_widget; - GtkWidget *welcome_box; - GtkWidget *title_label; - GtkWidget *status_label; - GtkWidget *instruction_label; + GtkWidget *stack; - GtkWidget *node_box; + GtkWidget *welcome_page; + GtkWidget *welcome_title_label; + GtkWidget *welcome_status_label; + GtkWidget *welcome_instruction_label; + + GtkWidget *node_page; GtkWidget *node_name_label; GtkWidget *node_type_label; GtkWidget *node_parent_label; GtkWidget *node_children_label; }; +/** + * @brief Affiche la page d'accueil. + */ static void workspace_show_welcome( Workspace *workspace ) @@ -38,14 +43,9 @@ static void workspace_show_welcome( return; } - gtk_widget_set_visible( - workspace->welcome_box, - TRUE - ); - - gtk_widget_set_visible( - workspace->node_box, - FALSE + gtk_stack_set_visible_child_name( + GTK_STACK(workspace->stack), + WORKSPACE_PAGE_WELCOME ); } @@ -76,76 +76,107 @@ Workspace *workspace_new(void) TRUE ); - workspace->welcome_box = gtk_box_new( + workspace->stack = gtk_stack_new(); + + if (workspace->stack == NULL) + { + workspace_free(workspace); + return NULL; + } + + gtk_widget_set_hexpand( + workspace->stack, + TRUE + ); + + gtk_widget_set_vexpand( + workspace->stack, + TRUE + ); + + gtk_box_append( + GTK_BOX(workspace->root_widget), + workspace->stack + ); + + /* + * Page d'accueil. + */ + workspace->welcome_page = gtk_box_new( GTK_ORIENTATION_VERTICAL, 12 ); - if (workspace->welcome_box == NULL) + if (workspace->welcome_page == NULL) { workspace_free(workspace); return NULL; } - /* - * Le conteneur d'accueil est centré horizontalement et verticalement - * dans l'espace disponible. - */ gtk_widget_set_halign( - workspace->welcome_box, + workspace->welcome_page, GTK_ALIGN_CENTER ); gtk_widget_set_valign( - workspace->welcome_box, + workspace->welcome_page, GTK_ALIGN_CENTER ); - workspace->title_label = gtk_label_new( + workspace->welcome_title_label = gtk_label_new( "Labfy Investigation" ); - workspace->status_label = gtk_label_new( + workspace->welcome_status_label = gtk_label_new( "Aucune enquête ouverte" ); - workspace->instruction_label = gtk_label_new( + workspace->welcome_instruction_label = gtk_label_new( "Sélectionnez ou créez une enquête" ); gtk_box_append( - GTK_BOX(workspace->welcome_box), - workspace->title_label + GTK_BOX(workspace->welcome_page), + workspace->welcome_title_label ); gtk_box_append( - GTK_BOX(workspace->welcome_box), - workspace->status_label + GTK_BOX(workspace->welcome_page), + workspace->welcome_status_label ); gtk_box_append( - GTK_BOX(workspace->welcome_box), - workspace->instruction_label + GTK_BOX(workspace->welcome_page), + workspace->welcome_instruction_label ); - workspace->node_box = gtk_box_new( - GTK_ORIENTATION_VERTICAL, - 12 + gtk_stack_add_named( + GTK_STACK(workspace->stack), + workspace->welcome_page, + WORKSPACE_PAGE_WELCOME ); - if (workspace->node_box == NULL) + /* + * Page d'informations sur le nœud. + */ + workspace->node_page = gtk_box_new( + GTK_ORIENTATION_VERTICAL, + 12 + ); + + if (workspace->node_page == NULL) { workspace_free(workspace); return NULL; } gtk_widget_set_halign( - workspace->node_box, + workspace->node_page, GTK_ALIGN_CENTER ); gtk_widget_set_valign( - workspace->node_box, + workspace->node_page, GTK_ALIGN_CENTER ); @@ -155,33 +186,29 @@ Workspace *workspace_new(void) workspace->node_children_label = gtk_label_new(NULL); gtk_box_append( - GTK_BOX(workspace->node_box), + GTK_BOX(workspace->node_page), workspace->node_name_label ); gtk_box_append( - GTK_BOX(workspace->node_box), + GTK_BOX(workspace->node_page), workspace->node_type_label ); gtk_box_append( - GTK_BOX(workspace->node_box), + GTK_BOX(workspace->node_page), workspace->node_parent_label ); gtk_box_append( - GTK_BOX(workspace->node_box), + GTK_BOX(workspace->node_page), workspace->node_children_label ); - gtk_box_append( - GTK_BOX(workspace->root_widget), - workspace->welcome_box - ); - - gtk_box_append( - GTK_BOX(workspace->root_widget), - workspace->node_box + gtk_stack_add_named( + GTK_STACK(workspace->stack), + workspace->node_page, + WORKSPACE_PAGE_NODE_INFORMATION ); workspace_show_welcome(workspace); @@ -212,7 +239,7 @@ void workspace_set_selected_node( InvestigationNodeType node_type; size_t children_count = 0; - char *type_text = NULL; + const char *type_text = NULL; char *parent_text = NULL; char *children_text = NULL; @@ -238,11 +265,11 @@ void workspace_set_selected_node( if (node_type == INVESTIGATION_NODE_DIRECTORY) { - type_text = g_strdup("Type : dossier"); + type_text = "Type : dossier"; } else { - type_text = g_strdup("Type : fichier"); + type_text = "Type : fichier"; } gtk_label_set_text( @@ -302,19 +329,13 @@ void workspace_set_selected_node( ); } - gtk_widget_set_visible( - workspace->welcome_box, - FALSE - ); - - gtk_widget_set_visible( - workspace->node_box, - TRUE + gtk_stack_set_visible_child_name( + GTK_STACK(workspace->stack), + WORKSPACE_PAGE_NODE_INFORMATION ); g_free(children_text); g_free(parent_text); - g_free(type_text); } void workspace_free(Workspace *workspace) @@ -324,9 +345,5 @@ void workspace_free(Workspace *workspace) return; } - /* - * Les widgets GTK sont intégrés dans l'arbre de widgets de MainWindow. - * GTK gère donc leur destruction. - */ g_free(workspace); }