From ac89c58ddb09ae8b27d8f914e5ebb2d86139e374 Mon Sep 17 00:00:00 2001 From: Frater <13979047+saintfrater@users.noreply.github.com> Date: Sat, 7 Feb 2026 00:20:32 +0100 Subject: [PATCH] sliders H & V --- doc/assets/Capture-2026-02-06-232336.png | Bin 0 -> 25238 bytes src/boot.asm | 22 +- src/drivers/gfx_cgam.asm | 88 +++--- src/services/gui_lib.asm | 343 +++++++++++++++++++---- 4 files changed, 360 insertions(+), 93 deletions(-) create mode 100644 doc/assets/Capture-2026-02-06-232336.png diff --git a/doc/assets/Capture-2026-02-06-232336.png b/doc/assets/Capture-2026-02-06-232336.png new file mode 100644 index 0000000000000000000000000000000000000000..773ba1e57ce86d6a025686cdeed782c0ae9a2fbe GIT binary patch literal 25238 zcmeHwdt8%s`#%N-=2y|I2ot7Z+BYmxER@40qGI1lo+mZ(Nm+`z=l8WhMH#S@VTGm+ z522E=W!OWCF_CN{Y!gwYfDAJm$YCIdaT?ngJ8^IKzMp&dHpdQ}#OIIS>-nR)rLoWP zdSCDBeO=e>!N0AEobuev=UiM|ro6X$#YZkK&!oDzOt|FnEci*-1-G}redGVkBvwYismmG}P^+nJzZtyMIhcEoSMbyqe zevRKqB6Hu_D^e@yg?}Z`NIU40UyA*e5F`C0qB}z(T)XypRIi17z6CMh38$H!A)4)Vvtg)hUi|A~Aw;qSWeYVd=F?LTSu|7iT^O1XPD z_(9p}L%X{~@93I6X&P0!L5|~cR1bHs~nzN)AzbXvO+^fxcd%HozhpbUPBe8)~8H(s4n?FWa7^I3psH?w@J= zO*c?Uh`DIk{Z0>j52L>)#!=q7`mA^%QKSr?hUtKur%ZdR zE-g+plNF{-*{uz#!d2*}F!pl0RV6~%jE&SN>>emK9?S4X4pA|YJhjCAUtQfRTcx@z zUIJ7`)aUh=&aT=iiKMnhGN`^O3wj4;Yg}d%u!|Q2WO=n=LK`1bs zs7u$iMseVhDa47#n58=~#rozP%riWxYJgBQzZinBREWXU#2@!eVpfDS?kdvX!lb;Z zJM?FirW#*JF+hz(lE`EqF)z_E&$gs3+erExY|jB&*!PAMC`$ilR2Ys@X6Rqbqe7WX zZ6^5oW14}3OwBnQ5k*!+)u}ib4MjkE*SHgf2QbePsUB`b%CuHRvgU0K8>{_V5XJnGmf*pag-%`bM;*;xJ$B@Iq;{#U!Zx&(mxc7DDSe!cS9I7_N!PwO|4Cf z2Cg=Y^;J>o6jrfXb(an9=UGpROtlFIbJ(8bD&AkZE{TM1`00cYn+VD4LgMf(QHPBy z|8fa-MiP0uEWfaO|7>jKEzeZVK)gX9B15wI+$PnVc>VdhPrvp2vguQv@>3>_*pv}p zL=i(=gNi|<$nHeq`W{O5OH-68iJ^>^2u0xw)rNwkHq{pfZAhF5?5H6TI;oyVbY+Gm zXkeVKq>j%NmFcR9G)R(7>sQYc%%6#%Tk*nmhO(oY%`zzr5Kh;>>uUG@rXXrd5LO@m zU(IRP*~M*dMk&b#{?&H=JsNYhKQak}Py(aSeH_lsmxM6!PTx3mR~{pJ2F zay#lg5r0*7+G`?tT5&giCY`J%($tbt3@p1(t5qZSmq~4cI_C2_R4O)4 zubOXYWfnI_v_;dD(L8FmQlKxysdX91rC8X$ayi$}=m}$EsB0RgBX{=jLMF!E89wq% zHU2-ZTNpQ^PkrlKoQLs1H@-ldX8gUv*IBe_H))zc_|xSw%(Npn1)+lDjbYUOqoJ(6 z#+aSI6Wb!=#q=uIa(aiPenK$5b~-03B-r!yke}EI?j7W9k^PCi9icz=9B8ca`B9PK zbFZ#2Te0u5UrGpZUsZJCieY}aN|TXRoTIKiZ}h>1zMA-#lAn*lE}*stMqz!Z?f02* z|9v;}oH9;ne^dxmdAg@E7xO~Anc@w3DRS>>BD!mC4DzKExIsKYv)F?{uA}~MXnWV% z?UfyKl4II9oTksE<>_GYS?=EKy+vIv9mPDC|=Dpj^to zh2WNe1LyeUOR?RDQ``9Y(Mo?$2ZN2|(hR*6n;RFlmtUUldtAH$doEg;%xJqHG#zW+ zVdnHoJ-A6@I2+pqWrYkn*gt*zaVfXUBak8gv&wNqk3eeMoSc;PMgz4N#V-Pn@6&ck zMVW;Ii!p&Is~OSB@c~Qfiu$rgXlRvm{=i3xE7C)*hhaN(1srgAHt3Zl2RCOOt1H@f z_k->b6jh^FC9kRuotn!_sCloeNhjjApjSuJYWFoaq^CFd^bdKq{?gHlNvfq8xY%>DAaa zqOZeq^XBy(UCX&3P%Mb%n0#NtwyIFS)x!En75h_tR%ULLVqtb#YjTEKm1;V`k-%0} z&ywJ;-nx?)*x6X*mr_5WR~{~AN;YY2fn0hRj14Xxm`84m2z9xIiwKPAHwCiZiIk)% zysB!>N&SoDUoUGHE{y{-iv6RApYD6PZxLn>T-%s|0bX+uL?re)#D34(a60b({0zh` z?BbV8Lmhfxhi1@2T{SJP{~o5ucmI0vuF}Q3ULjtDt3F6kYwkt#6_=ApC8l|d#CsDG zXZb8YwN;q8N7^twtk*@YaqM`BW#Z(M;Ars4x6QY+eM;LM_wU4_%%HCt1RghzV6Vku zSSPYQlU@qD!7X1JQ!3mA$y4U`-pvz5{8jsuc8aqggl?SG`IrY_hE|6b-yfJ-yoQcl znsO{weC)!ES)}y0iaKvfrLPTWd>e9kfhWdBe}*$9i-%qMAa@`mZKHC4j*1r{*P4;K77=jUf1#t zd1VbW?Q&JGbQXGYqa}%?+f#SzGO_0oE=v#jm@59#8bG2N^82#WE{3*77_HxKyXG;b z7YEmh;*`YgdDy%B!+>e5Z>*c_2+5szqmY7@j%nBC7FC@iN$DNC+^_Q8vuG&qM%m+e zFe!lTg1$LM2y_HPZci772lE-^0*4B$9ASH9V5-|&Rr>WbpOV@z8lk=GK6xzkI531h z_3ZnXyFa+5?mgg3+(#l;YYC)iDhM%9uzc(X>^FfqeX)20Koj&7#u<36{Qm_T7Fij= zn7%kz4L>~}M9`H-tWjRT3JQMcvWW*?7kHFyq?8}_9z8zTkm#YUz{>yGS-_tJH{gCV z$Krm?=W2?chP8w&xxc6B_JLyO2lr0R)S<7mLu%@(x78pr8%cy@6UuWOM+-S1b^;VPv?8tlF-W3-X~nYS zfvJTE3m*ylwT=F2ckS`mbbJ%x4-PT1|Egd&V2FmgOEdWd)58hXFj~zh6 zNCI>lIW%mm`%?G=<~l_5<@@;a6xZ_*@U=)b|DI)TLV{h3LV;SzQ$5X^D=jrh6g#3z zyUzEz8vcXp!No!FHg0nM?M8lqG^j&YW2MkJ5@Mtef&Oh{6NAp~^!xH21MD4p`@Uyt z6!tZ&9z#bmQS2y6*V?EVI7R6DM)3paazx)glPFcI)G##fLpMZInxF!y=w48OZ!MIh z()WgL?J?>;*@~mUoo3aBYr;aW3yZaPlJYuy?}p}`!2U`p!% zykCIiM2>ArZ_>`ZxIgjt z?kyp48r9QN_6~KGY=f^^6hPe>dXEv+b28bKgZL>_Kl^r6T0>452(`AA9Y!=Rp5mw} zPP?5qUxzeJE*|KsD5= zr5(J=&v1tP4+<2-GId(A)ARly)bAJcUW3F7O1x1+GI{j?nJGJR=n=tfGNKc272?-v zE=EmM@m{Z25b54v%XyRc@L8*iq3<{G1vTy+z6V)9zj9D0e{q8zCf%lrW4{a|(@qma z(yE9uR2dBRJP-7~OrNhrrLN?=Hv>~mY{Ihr#%RZU_bqqqb?T~1GDPG~)GsJLl<>PN z>j*ymZZCX0j3z!U*M|&*EDKtOqeZG9x^PmJCeRQ#C4DR5+<-oE3o%iDeAq%*ZI^+OTBq?Sy(Te;5JEG4s0nc zMit__T&J()rtQP_9C3czz;X!5#vI=WuNr1@Vxuc9fK2r{NX)q0E$?Xz`P&9T?7m(E z%0v^dwFtd;vVTsY^pttQ@)dNUUr*bPMTCj?g!U``)m|c8>o^|w2U~);9yB^HouCVT zUW(l&1X7%jA%7N2>c%r3d7x%vj9NKO!+v+E2J#gF(06he-v~S&(Y7xuUL)fmaD>Vo zL)kqj7h4JV{MQJdzuf&*Txf`E5srBtP9!w)vT3bJgx{b=r0XKpP-q84S3`p9qrIt8 zB>iGy)Mg+@F9Lcfk1u;3s3R!uYmI2WpZ+y7xzCVKX}^PneiHj1U$o_gmCR% zYE)AnS^0IInvS*%rFQU0~Y~z0bLm=&C zo|5LjI!tLOuUi6-myiJRcAkRN*Lp(NEpCV=fB5XIc5$88L0ahuoZQH+VJ<*CV?G%1 z=UraG>02Ac-CiYXU=EpbeFa&u@`zu5AHn zv_+26Xjkb{Z7{=?p&;!{j1+%~GAH*AT^xUUivI=S8Gf_rs^7FqHRbdkzyflbZX~CU zN$}u6gL&(OVZU4#5?lG2%sN^o)=!X8+W3kExs3~oeE5fr)eawryc(%qt$xUN<6(Gy zb<1{A+ImuXXYlEhpe<$UxkbK#+_WDRX6!|ZBSKnQdKPl&935rDD(PXHczGnTbA8E< z9~C9?l*-ruK|y8Wz6C}Z!MF)J?DP1w960~Fv|Z&jr6(AE)0gBAWj=sTy%x6h@rEH9 zf0ZT_S8*YzqQgm`H*_$4wMBDFK_Z3!_35@Neig>*fzPh^El*n)r+Vm-$7gv^BZ>MX zNs`aa9lJmQ5#sczFD7mcsk$Dvut+UE-G9_}Qxp$3$ObN+5?(&s=s4aTIg>B)iR@Up zh@BF4{Yp|6uE2}uSLAy(q5k>i?#rBfsYa0xC2eY+!;*Y9|Ach%^Rrm|b7?)H(*`N* zOfg}Da=SOjakLNM2dDrJLMJ;_<$AnCdVJiFnanb_MmL&XO8f;F;JC)L?>=utOD&`>Te2nK# zNyj69Ro`KJWQXh>Z?fdx(nMbxHW9-Tm1YWGzjWq~`fKSOdCCVVx2s%HAVYOla9gM+ z*T*B10jYTFxX$|7UiPuChRXFhmQ6ZG`oc}v67ANID|AiCtVp2xuzgvPH5J0GYuxoM z(JFPY>oq_oPxOG9tR4)hU?!3UNtC}Tc8t-EtYg>)x?lgt>sUN@9X+iWe(t8)bDb1_ zQV!xF?Rxif%_JO{Z(8>;?*ayd#m*Q zmk+?#Tl+dwYIi*EYiaT6Stw&Ng1xoSC{Pq!Oep|hVW9)o)Bt^UP%>s$V)lvT?ZHIE znB`l|ARy7L_)0;Oazg-X8$bd}&5ebmT1Fm8Qi2##dFYOu5(-g?z6TKJ+(pko^4W7R ze~jai&^>1TAX01_99a)ihFMt?S%Q@0Hxb|;oJK-CGDv6|gDjKiR(tz|;T8m3;o;

lmY{0y*xu}$65f^7(SF5ShVRBE~ zl?B+T}p&>YE-gBe)aY3Eg!2+bg@RQ)4$hdh|JJ%AdS z7`8m8?uO7OD^?^I$ExMmp2O1wB8l(S*XCWzwWbAL9)~;QkLBcxY6vNK^zB2usu4NIj~un%dX4$14Tty?SgrDDFXh+IShOgKBU4BAVjFmx{67hRZsgfLJf7;R%% zTjl$uCk!i9i2GZZ{!QQEA9=bfirfM5rb>;WVP6$quUNVrSO1cYT zVk!Xi*;KHgVT4(2vlQ}%wt9yzXIA_5yvFa2|B4n$T5!3SUsF_Nwt_{0Bw(y==hMjkIJm`Ct%HLe^7kg` z7;7?mR-{(t<5#zQNzq95zOBF06$e@!TjS|IYv}2j@b=H&ZcZk<4Zf& z-B~lYgPiies6srbV0o~+9t*es>yp=`Udr7to?#_KTCs?>C4eYPIf>8%N7aFYi3(pE z!MhN1bR;KwI=h3$a%dC=Nm%ibw-YMPDtJMcQ6!{(3&L9=;7ZxD;!=MUho4Q>j zv`hfinZDhZ~POk-@1S7WXO7(`+qq#IJ-z19~+iTD|oz~=&o}FeYVzga7DARiW>M>35wNWud z&*W9I7^L5&!nR)1aW#{(G9jiIR5OKrq#cdO(&k-qdX&Y7gMvbHO(pP1@Vz;ECe^Pd z`!v*yi?U+X_vJuLqcBc@%AVD2(c_`3Sast$fZ|jaJ4i&rpqcHe?57T_eZoQ8nP1gI9C^4R8rGP>uIY(DV4nAl1m! z;o|F|5OXacv)lcKsy;-UA}r#TMOMQKMi0V6T~eFo3sm19%eoK?jdrSfBQ;453to}1 zdYrGJ!y;E8sHKB~{-#xrx;x5776_c)%+Ps0Qb>*6(k@OTY-3{4L01GSMH>%p^uA=M z;$O4}BO{Hx+FUbWor@UlDvfR2LpJj|bJ1qyV8jS&39dj!)z~_0rvrmNWt+h5Nlb0{ zE9n55(aO^Cc8QKq>Zu{4S$#F9=${&RIC3gzLK_2e&)1KD-1Cu924u#%XghTqX+d-V zzGw<)EL?3U`!ef+_Jz&kZ(ELhB`QCTBGwqvhp8|3EK%9kqFZW8Mn^=3MItGj%0{xu15fp3{KY)(L$TxT+QqvV5DO#B|0$w1Xah3mV zRoG#9k%jG>0qiR*$9Hkoc`s*L$;hek(7)Zi5_Z;XA881#~E~c|)NY>Be zi0F=@OKZ~_FLQFrS;i7tI!1J7Oda*@<8(r39fb7`**%Yk4cRMa_UXMR_O*_h2W?ev zr1Ws7AE>AtVKO{MdMApW(_~%M9$I7jdhp7Q$%oQYM6bq*Auge zp<^g(gxIBe8PAV_xg$v5;{?en>?N$%BH0)<=t0B->V~83pOC&n%XY8({scg=9N)b>y z=cQEEU~JdRI5g9@4+Dp>(I9!NCv41DgSYIxY>YJR6X3&c0EnE1_>66_o3lKI<*h0s zKU7q=ay)>2p2mUCv2)`NKVw_Ci$*|~`;LM{&=4?X2`GpCjB$YL1-vuJ>-;Lk(~Zn} zaAwn*&y3;O78aZf2SeN#hmjumy#1Gt>~>q65WxepkUe=a8<| zVGYG11`T@>RwEz;2j^T@8uqK~?brqoXisbA#T~}oA5@Ms<~?_^|K>49LY$ouYKK3! zK?Un~RH6Or)(rroeYR;BaMn9M+OI`Fe?dK^$WPOwHuB@sLEi;E@(y?0n?APhN0+~z z1>U`cBufhy#Us6|qcTxzb9MG?WyXj@0exKKIE0PU#h4qQ$7P8B%-kUvdb)ewsG>KW z@Cr3lAyQZwIp(7>&m66WIvs#wL8P8<};X2SRIv_zRIfT!<{ z*WVRzX*a;{fH$IRnPj-s=SOJ;PowpW(s=P?#SoF)3Eo$I*Q=2#XVLmphoV^I67bg( zNLW`X_vY6adc*@x}T;xUzw#GBje7q053k z+I=DAmc-xCmeVHC=CGr<+=((ZMqqqbbmHzJy", 0 ; ----------------------------------------------------------- ; timer ISR (IRQ -> INT) diff --git a/src/drivers/gfx_cgam.asm b/src/drivers/gfx_cgam.asm index d59db9f..b373ef6 100644 --- a/src/drivers/gfx_cgam.asm +++ b/src/drivers/gfx_cgam.asm @@ -71,15 +71,13 @@ %define TXT_MODE 4 %define PUTCH 5 %define WRITE 6 -%define LINE_VERT 7 -%define LINE_HORIZ 8 -%define RECTANGLE 9 -%define RECTANGLE_FILL 10 -%define RECTANGLE_ROUND 11 -%define MOUSE_HIDE 12 -%define MOUSE_SHOW 13 -%define MOUSE_MOVE 14 -%define LINE 15 +%define LINE 7 +%define RECTANGLE 8 +%define RECTANGLE_FILL 9 +%define RECTANGLE_ROUND 10 +%define MOUSE_HIDE 11 +%define MOUSE_SHOW 12 +%define MOUSE_MOVE 13 ; ------------------------------------------------------------ ; COMMENTAIRE SUR LA MÉTHODE D'APPEL @@ -100,15 +98,14 @@ graph_driver: dw cga_set_writemode ; mode texte dw cga_putc ; dessin d'un caractère dw cga_write ; dessin d'une chaine de caractère - dw cga_line_vertical ; dessin d'une ligne verticale - dw cga_line_horizontal ; dessin d'une ligne horizontale + dw cga_line ; dessin d'une ligne (Bresenham) avec décision horizontale/verticale dw cga_draw_rect ; dessin d'un rectangle dw cga_fill_rect ; dessin d'un rectangle plein dw cga_draw_rounded_frame ; dessin d'un rectangle arrondi dw cga_mouse_hide ; déplacement du curseur dw cga_mouse_show ; déplacement du curseur dw cga_mouse_cursor_move ; déplacement du curseur - dw cga_line ; dessin d'une ligne (Bresenham) + ; ============================================================================= ; SECTION : PATTERNS & FILL @@ -790,6 +787,7 @@ cga_line_horizontal: %undef .x1 %undef .x2 %undef .y + ; ------------------------------------------------------------ ; cga_line (x1, y1, x2, y2, color) ; Algorithme de Bresenham pour tracer une ligne arbitraire @@ -803,6 +801,8 @@ cga_line_horizontal: cga_line: push bp mov bp, sp + pusha ; Sauvegarde de tous les registres (AX, BX, CX, DX, SI, DI) + push es ; Sauvegarde ES ; --- Optimisation : Lignes H/V --- mov ax, .y1 @@ -812,15 +812,24 @@ cga_line: cmp ax, .x2 je .do_vert - sub sp, 10 ; Variables locales: dx, dy, sx, sy, err - pusha - push es - + ; --- Bresenham --- mov ax, VIDEO_SEG mov es, ax call cga_mouse_hide + sub sp, 10 ; Variables locales: dx, dy, sx, sy, err + + ; --- Definitions locales --- + ; BP pointe sur l'ancien BP. + ; PUSHA (16 octets) + PUSH ES (2 octets) = 18 octets + ; Les variables locales commencent donc à BP-18 + %define .dx word [bp-20] + %define .dy word [bp-22] + %define .sx word [bp-24] + %define .sy word [bp-26] + %define .err word [bp-28] + ; --- Initialisation Bresenham --- ; dx = abs(x2 - x1), sx = sign(x2 - x1) mov ax, .x2 @@ -830,8 +839,8 @@ cga_line: neg ax neg bx ; sx = -1 .calc_dx: - mov [bp-2], ax ; save dx - mov [bp-6], bx ; save sx + mov .dx, ax ; save dx + mov .sx, bx ; save sx ; dy = abs(y2 - y1), sy = sign(y2 - y1) mov ax, .y2 @@ -841,13 +850,13 @@ cga_line: neg ax neg bx ; sy = -1 .calc_dy: - mov [bp-4], ax ; save dy - mov [bp-8], bx ; save sy + mov .dy, ax ; save dy + mov .sy, bx ; save sy ; err = dx - dy - mov ax, [bp-2] ; dx - sub ax, [bp-4] ; dy - mov [bp-10], ax ; err + mov ax, .dx ; dx + sub ax, .dy ; dy + mov .err, ax ; err ; Coordonnées courantes mov cx, .x1 @@ -878,32 +887,30 @@ cga_line: je .done .step: - mov ax, [bp-10] ; e2 = err + mov ax, .err ; e2 = err shl ax, 1 ; e2 = 2*err - mov bx, [bp-4] ; dy + mov bx, .dy ; dy neg bx ; -dy cmp ax, bx jle .check_y - add word [bp-10], bx ; err += -dy - add cx, [bp-6] ; x += sx + add .err, bx ; err += -dy + add cx, .sx ; x += sx .check_y: - mov bx, [bp-2] ; dx + mov bx, .dx ; dx cmp ax, bx jge .loop ; if e2 >= dx, skip y step - add word [bp-10], bx ; err += dx - add dx, [bp-8] ; y += sy + add .err, bx ; err += dx + add dx, .sy ; y += sy jmp .loop .done: call cga_mouse_show - pop es - popa - leave - ret + add sp, 10 ; Libération variables locales + jmp .exit .do_horiz: push word [bp+12] ; color @@ -912,8 +919,7 @@ cga_line: push word [bp+4] ; x1 call cga_line_horizontal add sp, 8 - pop bp - ret + jmp .exit .do_vert: push word [bp+12] ; color @@ -922,13 +928,23 @@ cga_line: push word [bp+4] ; x call cga_line_vertical add sp, 8 + +.exit: + pop es + popa pop bp ret + %undef .x1 %undef .y1 %undef .x2 %undef .y2 %undef .color +%undef .dx +%undef .dy +%undef .sx +%undef .sy +%undef .err ; ------------------------------------------------------------ ; cga_draw_rect diff --git a/src/services/gui_lib.asm b/src/services/gui_lib.asm index b0c8fd7..4593f95 100644 --- a/src/services/gui_lib.asm +++ b/src/services/gui_lib.asm @@ -20,6 +20,10 @@ ; ; ============================================================================= +; +; https://github.com/buserror/libmui +; + ; --- Configuration --- %define GUI_RAM_SEG 0x0A00 ; Segment de données UI %define GUI_MAX_WIDGETS 32 ; Nombre max de widgets simultanés @@ -44,6 +48,9 @@ ; --- Widgets attributs --- %define BUTTON_OK 1 +%define SLIDER_HORIZONTAL 1 +%define SLIDER_VERTICAL 2 + ; --- Structure d'un OBJET (Bouton, etc) --- struc widget .state resb 1 ; État (0=libre, >0=utilisé) @@ -371,55 +378,157 @@ gui_logic_slider: mov byte [gs:si + widget.state], GUI_STATE_PRESSED - ; Calcul de l'ancrage + ; --- CALCUL TAILLE THUMB POUR HIT TEST --- + ; On doit savoir si le clic est SUR le curseur ou SUR la piste + push ax + push bx + push dx + + xor ax, ax + xor bx, bx + + cmp byte [gs:si + widget.attr_mode], 2 + je .calc_v + + ; --- Horizontal --- + mov ax, [gs:si + widget.w] + mov bl, [gs:si + widget.thumb_pct] + mul bx + mov bx, 100 + div bx ; AX = Thumb Width + + ; Check collision avec le thumb actuel + mov bx, [gs:si + widget.attr_val] + cmp cx, bx + jb .click_outside_h ; Click avant le thumb + add bx, ax + cmp cx, bx + ja .click_outside_h ; Click après le thumb + + ; Click DANS le thumb : Anchor = MouseX - AttrVal mov ax, cx sub ax, [gs:si + widget.attr_val] mov [gs:si + widget.attr_anchor], ax - cmp byte [gs:si + widget.attr_mode], 2 - jne .do_drag + jmp .init_done + + .click_outside_h: + ; Click HORS du thumb : On centre le thumb sur la souris + shr ax, 1 + mov [gs:si + widget.attr_anchor], ax + jmp .init_done + + .calc_v: + ; --- Vertical --- + mov ax, [gs:si + widget.h] + mov bl, [gs:si + widget.thumb_pct] + mul bx + mov bx, 100 + div bx ; AX = Thumb Height + + ; Check collision avec le thumb actuel + mov bx, [gs:si + widget.attr_val] + cmp dx, bx + jb .click_outside_v + add bx, ax + cmp dx, bx + ja .click_outside_v + + ; Click DANS le thumb mov ax, dx sub ax, [gs:si + widget.attr_val] mov [gs:si + widget.attr_anchor], ax + jmp .init_done + + .click_outside_v: + ; Click HORS du thumb + shr ax, 1 + mov [gs:si + widget.attr_anchor], ax + + .init_done: + pop dx + pop bx + pop ax .do_drag: ; --- LOGIQUE DE DÉPLACEMENT --- + ; On calcule les limites dynamiquement pour éviter que le curseur ne sorte + push ax + push bx + push dx + + xor ax, ax + xor bx, bx + cmp byte [gs:si + widget.attr_mode], 1 je .drag_h cmp byte [gs:si + widget.attr_mode], 2 je .drag_v + + pop dx + pop bx + pop ax xor ax, ax ret .drag_h: + ; 1. Thumb Width -> AX + mov ax, [gs:si + widget.w] + mov bl, [gs:si + widget.thumb_pct] + mul bx + mov bx, 100 + div bx ; AX = Thumb Width + + ; 2. Max Pos = X + W - ThumbWidth + mov bx, [gs:si + widget.x] + add bx, [gs:si + widget.w] + sub bx, ax ; BX = Max Pos + + ; 3. Min Pos = X + mov dx, [gs:si + widget.x] ; DX = Min Pos + + ; 4. Target Pos = MouseX - Anchor mov ax, cx - sub ax, [gs:si + widget.attr_anchor] ; Nouvelle pos = MouseX - Anchor - ; Clamp Min - cmp ax, [gs:si + widget.attr_min] - jge .chk_max_h - mov ax, [gs:si + widget.attr_min] - .chk_max_h: - ; Clamp Max - cmp ax, [gs:si + widget.attr_max] - jle .apply_pos - mov ax, [gs:si + widget.attr_max] - jmp .apply_pos + sub ax, [gs:si + widget.attr_anchor] + jmp .apply_clamp .drag_v: - mov ax, dx - sub ax, [gs:si + widget.attr_anchor] - ; Clamp Min - cmp ax, [gs:si + widget.attr_min] - jge .chk_max_v - mov ax, [gs:si + widget.attr_min] + ; 1. Thumb Height -> AX + mov ax, [gs:si + widget.h] + mov bl, [gs:si + widget.thumb_pct] + mul bx + mov bx, 100 + div bx ; AX = Thumb Height - .chk_max_v: - ; Clamp Max - cmp ax, [gs:si + widget.attr_max] - jle .apply_pos - mov ax, [gs:si + widget.attr_max] + ; 2. Max Pos = Y + H - ThumbHeight + mov bx, [gs:si + widget.y] + add bx, [gs:si + widget.h] + sub bx, ax ; BX = Max Pos + + ; 3. Min Pos = Y + mov dx, [gs:si + widget.y] ; DX = Min Pos + + ; 4. Target Pos = MouseY - Anchor + ; MouseY est sur la pile (push dx initial), on le recupere via SP + mov bp, sp + mov ax, [bp] ; [bp] = Saved DX (MouseY) + sub ax, [gs:si + widget.attr_anchor] + + .apply_clamp: + ; AX = Target, DX = Min, BX = Max + cmp ax, dx + jge .chk_max + mov ax, dx jmp .apply_pos + .chk_max: + cmp ax, bx + jle .apply_pos + mov ax, bx .apply_pos: + pop dx + pop bx + add sp, 2 ; Clean AX from stack + cmp ax, [gs:si + widget.attr_val] je .no_change mov [gs:si + widget.attr_val], ax @@ -471,7 +580,6 @@ gui_logic_checkbox: ret - ; Dessine le widget pointé par SI gui_draw_single_widget: pusha @@ -525,23 +633,36 @@ gui_draw_single_widget: .case_5: - .done: GFX MOUSE_SHOW ; On réaffiche la souris APRES, capturant le widget fini popa ret +; --- Locals Mapping --- +%define .thumb_x1 word [bp-2] +%define .thumb_y1 word [bp-4] +%define .thumb_x2 word [bp-6] +%define .thumb_y2 word [bp-8] +%define .track_x1 word [bp-10] +%define .track_y1 word [bp-12] +%define .track_x2 word [bp-14] +%define .track_y2 word [bp-16] draw_slider: + push bp + mov bp, sp + sub sp, 16 ; Reserve space for locals + + ; Save track coords (Arguments passed in AX, BX, CX, DX) + mov .track_x1, ax + mov .track_y1, bx + mov .track_x2, cx + mov .track_y2, dx + ; 1. Dessiner la piste (Track) - GFX RECTANGLE_FILL, ax, bx, cx, dx, PATTERN_WHITE_LIGHT - GFX RECTANGLE, ax, bx, cx, dx, 0 + GFX RECTANGLE_FILL, .track_x1, .track_y1, .track_x2, .track_y2, PATTERN_WHITE_LIGHT + GFX RECTANGLE, .track_x1, .track_y1, .track_x2, .track_y2, 0 ; 2. Calculer la taille du curseur (Thumb) - push ax ; Sauvegarde coords track (X1, Y1, X2, Y2) - push bx - push cx - push dx - cmp byte [gs:si + widget.attr_mode], 2 je .calc_v @@ -553,12 +674,34 @@ draw_slider: mov bx, 100 div bx ; AX = Thumb Width - mov bx, [gs:si + widget.y] ; BX = Y1 - mov dx, bx - add dx, [gs:si + widget.h] ; DX = Y2 - mov cx, [gs:si + widget.attr_val] ; CX = X1 - add ax, cx ; AX = X1 + Width = X2 - xchg ax, cx ; AX = X1, CX = X2 + ; Thumb X1 = attr_val + mov cx, [gs:si + widget.attr_val] + + ; --- CLAMP X1 (Fix Overflow) --- + ; Max X1 = TrackX2 - ThumbW + mov dx, .track_x2 + sub dx, ax ; DX = Max X1 + cmp cx, dx + jle .chk_min_x + mov cx, dx + .chk_min_x: + cmp cx, .track_x1 + jge .ok_x1 + mov cx, .track_x1 + .ok_x1: + mov .thumb_x1, cx + + ; Thumb X2 = X1 + Width + add cx, ax + mov .thumb_x2, cx + + ; Thumb Y1 = Track Y1 + mov ax, .track_y1 + mov .thumb_y1, ax + + ; Thumb Y2 = Track Y2 + mov ax, .track_y2 + mov .thumb_y2, ax jmp .draw_thumb .calc_v: @@ -570,23 +713,119 @@ draw_slider: mov bx, 100 div bx ; AX = Thumb Height - mov bx, [gs:si + widget.attr_val] ; BX = Y1 - mov dx, bx - add dx, ax ; DX = Y2 - mov ax, [gs:si + widget.x] ; AX = X1 - mov cx, ax - add cx, [gs:si + widget.w] ; CX = X2 + ; Thumb Y1 = attr_val + mov cx, [gs:si + widget.attr_val] + + ; --- CLAMP Y1 (Fix Overflow) --- + ; Max Y1 = TrackY2 - ThumbH + mov dx, .track_y2 + sub dx, ax ; DX = Max Y1 + cmp cx, dx + jle .chk_min_y + mov cx, dx + .chk_min_y: + cmp cx, .track_y1 + jge .ok_y1 + mov cx, .track_y1 + .ok_y1: + mov .thumb_y1, cx + + ; Thumb Y2 = Y1 + Height + add cx, ax + mov .thumb_y2, cx + + ; Thumb X1 = Track X1 + mov ax, .track_x1 + mov .thumb_x1, ax + + ; Thumb X2 = Track X2 + mov ax, .track_x2 + mov .thumb_x2, ax .draw_thumb: ; 3. Dessiner le curseur (Thumb) - GFX RECTANGLE_FILL, ax, bx, cx, dx, PATTERN_WHITE - GFX RECTANGLE, ax, bx, cx, dx, 0 - add sp, 8 ; Nettoyer la pile des push ax..dx - GFX TXT_MODE, GFX_TXT_BLACK_TRANSPARENT - call draw_text + GFX RECTANGLE_FILL, .thumb_x1, .thumb_y1, .thumb_x2, .thumb_y2, PATTERN_WHITE + GFX RECTANGLE, .thumb_x1, .thumb_y1, .thumb_x2, .thumb_y2, 0 + + ; --- Grip Lines (3 lignes pour un look moderne) --- + cmp byte [gs:si + widget.attr_mode], 2 + je .grip_v + + ; --- Grip Horizontal (Lignes verticales) --- + ; Center X + mov ax, .thumb_x1 + add ax, .thumb_x2 + shr ax, 1 ; AX = Center X + + ; Y bounds (padding 3px) + mov bx, .thumb_y1 + add bx, 3 + mov dx, .thumb_y2 + sub dx, 3 + + ; Center Line + GFX LINE, ax, bx, ax, dx, 0 + + ; Left Line + mov cx, ax + sub cx, 2 + cmp cx, .thumb_x1 + jle .skip_left + GFX LINE, cx, bx, cx, dx, 0 + .skip_left: + + ; Right Line + mov cx, ax + add cx, 2 + cmp cx, .thumb_x2 + jge .grip_done + GFX LINE, cx, bx, cx, dx, 0 + jmp .grip_done + + .grip_v: + ; --- Grip Vertical (Lignes horizontales) --- + ; Center Y + mov bx, .thumb_y1 + add bx, .thumb_y2 + shr bx, 1 ; BX = Center Y + + ; X bounds (padding 3px) + mov ax, .thumb_x1 + add ax, 3 + mov cx, .thumb_x2 + sub cx, 3 + + ; Center Line + GFX LINE, ax, bx, cx, bx, 0 + + ; Top Line + mov dx, bx + sub dx, 2 + cmp dx, .thumb_y1 + jle .skip_top + GFX LINE, ax, dx, cx, dx, 0 + .skip_top: + + ; Bottom Line + mov dx, bx + add dx, 2 + cmp dx, .thumb_y2 + jge .grip_done + GFX LINE, ax, dx, cx, dx, 0 + + .grip_done: + leave ret - +; Clean up defines +%undef .thumb_x1 +%undef .thumb_y1 +%undef .thumb_x2 +%undef .thumb_y2 +%undef .track_x1 +%undef .track_y1 +%undef .track_x2 +%undef .track_y2 draw_button: ; Dispatch selon état