gui - wip
This commit is contained in:
parent
259dc3697d
commit
88debea9f9
5 changed files with 225 additions and 199 deletions
|
|
@ -21,7 +21,7 @@
|
|||
; =============================================================================
|
||||
|
||||
; --- Configuration Mémoire ---
|
||||
%define GUI_RAM_SEG 0x0800 ; Segment de données UI
|
||||
%define GUI_RAM_SEG 0x0A00 ; Segment de données UI
|
||||
%define GUI_MAX_WIDGETS 32 ; Nombre max de widgets simultanés
|
||||
|
||||
; --- Drapeaux & États ---
|
||||
|
|
@ -39,7 +39,6 @@ struc widget
|
|||
.y resw 1 ; Position Y
|
||||
.w resw 1 ; Largeur
|
||||
.h resw 1 ; Hauteur
|
||||
.state resb 1 ; État (0=Normal, 1=Hover, 2=Pressed, 3=Disabled)
|
||||
.text_ofs resw 1 ; Offset du texte
|
||||
.text_seg resw 1 ; Segment du texte
|
||||
.event_click resw 1 ; adresse de la fonction "on click"
|
||||
|
|
@ -60,42 +59,46 @@ endstruc
|
|||
; Entrée : DS doit pointer vers GUI_RAM_SEG
|
||||
; -----------------------------------------------------------------------------
|
||||
gui_init_system:
|
||||
pushad
|
||||
push ds
|
||||
push eax
|
||||
push cx
|
||||
push es
|
||||
push di
|
||||
|
||||
mov ax, GUI_RAM_SEG
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
|
||||
mov di, 0 ; On commence au début du segment 0x0800
|
||||
xor di, di
|
||||
mov cx, (widget_size * GUI_MAX_WIDGETS)
|
||||
shl cx, 2 ; cx / 4
|
||||
xor eax, eax
|
||||
rep stosd ; Remplit tout de 0
|
||||
|
||||
pop ds
|
||||
popad
|
||||
pop di
|
||||
pop es
|
||||
pop cx
|
||||
pop eax
|
||||
ret
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; gui_alloc_widget
|
||||
; Cherche un slot vide et retourne son adresse
|
||||
; Sortie :
|
||||
; - Succès : CF=0 (Carry Clear), SI = Offset du widget
|
||||
; - Echec : CF=1 (Carry Set), SI = Indéfini (ou 0)
|
||||
; - Succès : CF=0 (Carry Clear), DS:SI = Offset du widget
|
||||
; - Echec : CF=1 (Carry Set), DS:SI = Indéfini (ou 0)
|
||||
; -----------------------------------------------------------------------------
|
||||
gui_alloc_widget:
|
||||
push ax
|
||||
push cx
|
||||
push bx
|
||||
push ds
|
||||
|
||||
mov ax, GUI_RAM_SEG
|
||||
mov ds, ax
|
||||
mov gs, ax
|
||||
|
||||
mov si, 0 ; Début du pool
|
||||
mov cx, GUI_MAX_WIDGETS
|
||||
|
||||
.loop_find:
|
||||
cmp byte [si + widget.state], GUI_STATE_FREE
|
||||
cmp byte [gs:si + widget.state], GUI_STATE_FREE
|
||||
je .found ; Si state == 0, c'est libre !
|
||||
|
||||
add si, widget_size ; Sinon on passe au suivant
|
||||
|
|
@ -107,16 +110,16 @@ gui_alloc_widget:
|
|||
|
||||
.found:
|
||||
; On initialise le slot trouvé
|
||||
mov byte [si + widget.state], GUI_STATE_NORMAL ; Marquer comme occupé
|
||||
mov byte [gs:si + widget.state], GUI_STATE_NORMAL ; Marquer comme occupé
|
||||
|
||||
; Reset des champs critiques pour éviter les déchets
|
||||
mov word [si + widget.callback], 0
|
||||
mov word [gs:si + widget.event_click], 0
|
||||
|
||||
clc ; Clear Carry Flag
|
||||
.done:
|
||||
pop ds
|
||||
pop bx
|
||||
pop cx
|
||||
pop ax
|
||||
ret
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
|
|
@ -125,11 +128,25 @@ gui_alloc_widget:
|
|||
; Entrée : SI = Pointeur widget
|
||||
; -----------------------------------------------------------------------------
|
||||
gui_free_widget:
|
||||
mov byte [si + widget.state], GUI_STATE_FREE
|
||||
push eax
|
||||
push es
|
||||
|
||||
mov ax, GUI_RAM_SEG
|
||||
mov es, ax
|
||||
|
||||
xor di, di
|
||||
mov cx, (widget_size)
|
||||
shl cx, 2 ; cx / 4
|
||||
xor eax, eax
|
||||
rep stosd ; Remplit tout de 0
|
||||
|
||||
mov byte [gs:si + widget.state], GUI_STATE_FREE
|
||||
; On efface visuellement le widget (optionnel, remplit de blanc)
|
||||
; Pour l'instant on le marque juste libre, il sera redessiné par-dessus.
|
||||
ret
|
||||
|
||||
pop es
|
||||
pop eax
|
||||
ret
|
||||
|
||||
; =============================================================================
|
||||
; SECTION : MOTEUR D'ÉVÉNEMENTS (EVENT LOOP)
|
||||
|
|
@ -146,31 +163,46 @@ gui_free_widget:
|
|||
; -----------------------------------------------------------------------------
|
||||
gui_process_all:
|
||||
pusha
|
||||
push gs
|
||||
|
||||
mov ax, BDA_DATA_SEG
|
||||
mov ds, ax
|
||||
|
||||
mov cx, [BDA_MOUSE + mouse.x]
|
||||
mov dx, [BDA_MOUSE + mouse.y]
|
||||
mov bl, [BDA_MOUSE + mouse.status]
|
||||
|
||||
mov ax, GUI_RAM_SEG
|
||||
mov gs, ax
|
||||
|
||||
mov si, 0 ; Pointeur début tableau
|
||||
mov di, GUI_MAX_WIDGETS ; Compteur
|
||||
|
||||
.loop_widgets:
|
||||
; Est-ce que ce slot est occupé ?
|
||||
cmp byte [si + widget.state], GUI_STATE_FREE
|
||||
cmp byte [gs:si + widget.state], GUI_STATE_FREE
|
||||
je .next_widget
|
||||
|
||||
; mov ah, [gs:si + widget.state] ; AH = Ancien état du widget
|
||||
|
||||
; --- Logique Widget ---
|
||||
push bx ; Sauver état boutons souris
|
||||
;push bx ; Sauver état boutons souris
|
||||
push ax
|
||||
call gui_update_logic ; Vérifier collision/clic
|
||||
;pop ax
|
||||
|
||||
; Si AL=1 (Clic relâché validé), exécuter le callback
|
||||
cmp al, 1
|
||||
jne .no_action
|
||||
|
||||
; Vérifier si un callback est défini
|
||||
cmp word [si + widget.callback], 0
|
||||
cmp word [gs:si + widget.event_click], 0
|
||||
je .no_action
|
||||
|
||||
; APPEL DU CALLBACK (Fonction utilisateur)
|
||||
; On sauve les registres car le callback peut faire n'importe quoi
|
||||
pusha
|
||||
call word [si + widget.callback]
|
||||
call word [gs:si + widget.event_click]
|
||||
popa
|
||||
|
||||
.no_action:
|
||||
|
|
@ -184,6 +216,7 @@ gui_process_all:
|
|||
dec di
|
||||
jnz .loop_widgets
|
||||
|
||||
pop ds
|
||||
popa
|
||||
ret
|
||||
|
||||
|
|
@ -193,25 +226,25 @@ gui_process_all:
|
|||
|
||||
; (Interne) Met à jour l'état d'un seul widget
|
||||
; Entrée : SI=Widget, CX=MouseX, DX=MouseY, BL=Buttons
|
||||
; Sortie : AL=1 si Clicked, 0 sinon. Met à jour [SI].state
|
||||
; Sortie : AL=1 si Clicked, 0 sinon. Met à jour [gs:si].state
|
||||
gui_update_logic:
|
||||
xor ax, ax
|
||||
|
||||
cmp byte [si + widget.state], GUI_STATE_DISABLED
|
||||
cmp byte [gs:si + widget.state], GUI_STATE_DISABLED
|
||||
je .done
|
||||
|
||||
; --- Hit Test ---
|
||||
cmp cx, [si + widget.x]
|
||||
cmp cx, [gs:si + widget.x]
|
||||
jl .miss
|
||||
mov bp, [si + widget.x]
|
||||
add bp, [si + widget.w]
|
||||
mov bp, [gs:si + widget.x]
|
||||
add bp, [gs:si + widget.w]
|
||||
cmp cx, bp
|
||||
jg .miss
|
||||
|
||||
cmp dx, [si + widget.y]
|
||||
cmp dx, [gs:si + widget.y]
|
||||
jl .miss
|
||||
mov bp, [si + widget.y]
|
||||
add bp, [si + widget.h]
|
||||
mov bp, [gs:si + widget.y]
|
||||
add bp, [gs:si + widget.h]
|
||||
cmp dx, bp
|
||||
jg .miss
|
||||
|
||||
|
|
@ -220,26 +253,26 @@ gui_update_logic:
|
|||
jz .released
|
||||
|
||||
; Clic enfoncé
|
||||
mov byte [si + widget.state], GUI_STATE_PRESSED
|
||||
mov byte [gs:si + widget.state], GUI_STATE_PRESSED
|
||||
jmp .done
|
||||
|
||||
.released:
|
||||
.released:
|
||||
; Bouton relâché. Était-il pressé avant ?
|
||||
cmp byte [si + widget.state], GUI_STATE_PRESSED
|
||||
cmp byte [gs:si + widget.state], GUI_STATE_PRESSED
|
||||
jne .hover
|
||||
|
||||
; Clic validé !
|
||||
mov al, 1
|
||||
mov byte [si + widget.state], GUI_STATE_HOVER
|
||||
mov byte [gs:si + widget.state], GUI_STATE_HOVER
|
||||
jmp .done
|
||||
|
||||
.hover:
|
||||
mov byte [si + widget.state], GUI_STATE_HOVER
|
||||
.hover:
|
||||
mov byte [gs:si + widget.state], GUI_STATE_HOVER
|
||||
jmp .done
|
||||
|
||||
.miss:
|
||||
mov byte [si + widget.state], GUI_STATE_NORMAL
|
||||
.done:
|
||||
.miss:
|
||||
mov byte [gs:si + widget.state], GUI_STATE_NORMAL
|
||||
.done:
|
||||
ret
|
||||
|
||||
; (Interne) Dessine le widget pointé par SI
|
||||
|
|
@ -247,10 +280,10 @@ gui_draw_single_widget:
|
|||
pusha
|
||||
|
||||
; Chargement coords
|
||||
mov ax, [si + widget.x]
|
||||
mov bx, [si + widget.y]
|
||||
mov cx, [si + widget.w]
|
||||
mov dx, [si + widget.h]
|
||||
mov ax, [gs:si + widget.x]
|
||||
mov bx, [gs:si + widget.y]
|
||||
mov cx, [gs:si + widget.w]
|
||||
mov dx, [gs:si + widget.h]
|
||||
|
||||
; Calcul X2, Y2
|
||||
mov di, ax
|
||||
|
|
@ -259,19 +292,19 @@ gui_draw_single_widget:
|
|||
add bp, dx
|
||||
|
||||
; Dispatch selon état
|
||||
mov al, [si + widget.state]
|
||||
mov al, [gs:si + widget.state]
|
||||
cmp al, GUI_STATE_PRESSED
|
||||
je .paint_pressed
|
||||
cmp al, GUI_STATE_HOVER
|
||||
je .paint_hover
|
||||
|
||||
.paint_normal:
|
||||
.paint_normal:
|
||||
GFX RECTANGLE_FILL, ax, bx, di, bp, 1 ; Blanc
|
||||
GFX RECTANGLE_DRAW, ax, bx, di, bp, 0 ; Bord Noir
|
||||
GFX TXT_MODE, GFX_TXT_BLACK_TRANSPARENT
|
||||
jmp .text
|
||||
|
||||
.paint_hover:
|
||||
.paint_hover:
|
||||
GFX RECTANGLE_FILL, ax, bx, di, bp, 1
|
||||
GFX RECTANGLE_DRAW, ax, bx, di, bp, 0
|
||||
; Effet gras
|
||||
|
|
@ -282,36 +315,38 @@ gui_draw_single_widget:
|
|||
GFX RECTANGLE_DRAW, ax, bx, di, bp, 0
|
||||
|
||||
; Restauration coords pour le texte
|
||||
mov ax, [si + widget.x]
|
||||
mov bx, [si + widget.y]
|
||||
mov ax, [gs:si + widget.x]
|
||||
mov bx, [gs:si + widget.y]
|
||||
jmp .text_setup
|
||||
|
||||
.paint_pressed:
|
||||
.paint_pressed:
|
||||
GFX RECTANGLE_FILL, ax, bx, di, bp, 0 ; Noir
|
||||
GFX TXT_MODE, GFX_TXT_WHITE_TRANSPARENT
|
||||
jmp .text
|
||||
|
||||
.text_setup:
|
||||
.text_setup:
|
||||
; Petit hack pour recentrer le texte après l'effet gras
|
||||
mov cx, [si + widget.w]
|
||||
mov dx, [si + widget.h]
|
||||
mov cx, [gs:si + widget.w]
|
||||
mov dx, [gs:si + widget.h]
|
||||
|
||||
.text:
|
||||
.text:
|
||||
; --- Centrage Texte (Simplifié) ---
|
||||
push si
|
||||
mov es, [si + widget.text_seg]
|
||||
mov di, [si + widget.text_ofs]
|
||||
mov es, [gs:si + widget.text_seg]
|
||||
mov di, [gs:si + widget.text_ofs]
|
||||
xor cx, cx
|
||||
.strlen:
|
||||
|
||||
.strlen:
|
||||
cmp byte [es:di], 0
|
||||
je .calc
|
||||
inc cx
|
||||
inc di
|
||||
jmp .strlen
|
||||
.calc:
|
||||
|
||||
.calc:
|
||||
shl cx, 3 ; Largeur texte px
|
||||
push ax ; Sauve X original
|
||||
mov ax, [si + widget.w]
|
||||
mov ax, [gs:si + widget.w]
|
||||
sub ax, cx
|
||||
shr ax, 1
|
||||
pop bx ; Récupère X original dans BX (oups, on veut ajouter)
|
||||
|
|
@ -319,17 +354,17 @@ gui_draw_single_widget:
|
|||
|
||||
push ax ; X final prêt
|
||||
|
||||
mov bx, [si + widget.h]
|
||||
mov bx, [gs:si + widget.h]
|
||||
sub bx, 8
|
||||
shr bx, 1
|
||||
add bx, [si + widget.y] ; Y final
|
||||
add bx, [gs:si + widget.y] ; Y final
|
||||
|
||||
pop cx ; CX = X Final, BX = Y Final
|
||||
|
||||
GFX GOTOXY, cx, bx
|
||||
|
||||
mov dx, [si + widget.text_seg]
|
||||
mov ax, [si + widget.text_ofs]
|
||||
mov dx, [gs:si + widget.text_seg]
|
||||
mov ax, [gs:si + widget.text_ofs]
|
||||
GFX WRITE, dx, ax
|
||||
|
||||
pop si
|
||||
|
|
@ -347,10 +382,10 @@ gui_draw_button:
|
|||
pusha
|
||||
|
||||
; Charger les propriétés depuis la structure
|
||||
mov ax, [si + widget.x]
|
||||
mov bx, [si + widget.y]
|
||||
mov cx, [si + widget.w]
|
||||
mov dx, [si + widget.h]
|
||||
mov ax, [gs:si + widget.x]
|
||||
mov bx, [gs:si + widget.y]
|
||||
mov cx, [gs:si + widget.w]
|
||||
mov dx, [gs:si + widget.h]
|
||||
|
||||
; Calculer X2 et Y2 pour le rectangle
|
||||
mov di, ax ; X1
|
||||
|
|
@ -359,13 +394,13 @@ gui_draw_button:
|
|||
add bp, dx ; Y2 = Y + H
|
||||
|
||||
; Vérifier l'état
|
||||
cmp byte [si + widget.state], GUI_STATE_PRESSED
|
||||
cmp byte [gs:si + widget.state], GUI_STATE_PRESSED
|
||||
je .draw_pressed
|
||||
|
||||
cmp byte [si + widget.state], GUI_STATE_HOVER
|
||||
cmp byte [gs:si + widget.state], GUI_STATE_HOVER
|
||||
je .draw_hover
|
||||
|
||||
cmp byte [si + widget.state], GUI_STATE_DISABLED
|
||||
cmp byte [gs:si + widget.state], GUI_STATE_DISABLED
|
||||
je .draw_disabled
|
||||
|
||||
.draw_normal:
|
||||
|
|
@ -392,10 +427,10 @@ gui_draw_button:
|
|||
GFX RECTANGLE_DRAW, ax, bx, di, bp, 0
|
||||
|
||||
; Restaurer les coords pour le texte
|
||||
mov ax, [si + widget.x]
|
||||
mov bx, [si + widget.y]
|
||||
mov ax, [gs:si + widget.x]
|
||||
mov bx, [gs:si + widget.y]
|
||||
mov di, ax
|
||||
add di, [si + widget.w]
|
||||
add di, [gs:si + widget.w]
|
||||
|
||||
GFX TXT_MODE, GFX_TXT_BLACK_TRANSPARENT
|
||||
jmp .draw_text
|
||||
|
|
@ -425,8 +460,8 @@ gui_draw_button:
|
|||
|
||||
push si
|
||||
; 1. Calculer longueur chaine
|
||||
mov es, [si + widget.text_seg]
|
||||
mov di, [si + widget.text_ofs]
|
||||
mov es, [gs:si + widget.text_seg]
|
||||
mov di, [gs:si + widget.text_ofs]
|
||||
xor cx, cx
|
||||
|
||||
.strlen:
|
||||
|
|
@ -440,21 +475,21 @@ gui_draw_button:
|
|||
; CX = Longueur chaine
|
||||
shl cx, 3 ; CX * 8 (largeur en pixels du texte)
|
||||
|
||||
mov ax, [si + widget.w]
|
||||
mov ax, [gs:si + widget.w]
|
||||
sub ax, cx ; Marge horizontale totale
|
||||
shr ax, 1 ; Diviser par 2
|
||||
add ax, [si + widget.x] ; X final
|
||||
add ax, [gs:si + widget.x] ; X final
|
||||
|
||||
mov bx, [si + widget.h]
|
||||
mov bx, [gs:si + widget.h]
|
||||
sub bx, 8 ; Hauteur fonte (8px)
|
||||
shr bx, 1 ; Diviser par 2
|
||||
add bx, [si + widget.y] ; Y final
|
||||
add bx, [gs:si + widget.y] ; Y final
|
||||
|
||||
; 2. Dessiner
|
||||
GFX GOTOXY, ax, bx
|
||||
|
||||
mov dx, [si + widget.text_seg]
|
||||
mov ax, [si + widget.text_ofs]
|
||||
mov dx, [gs:si + widget.text_seg]
|
||||
mov ax, [gs:si + widget.text_ofs]
|
||||
GFX WRITE, dx, ax
|
||||
|
||||
pop si
|
||||
|
|
@ -482,27 +517,27 @@ gui_update_button:
|
|||
xor ax, ax ; AL = Return value (0)
|
||||
|
||||
; Si désactivé, on ne fait rien
|
||||
cmp byte [si + widget.state], GUI_STATE_DISABLED
|
||||
cmp byte [gs:si + widget.state], GUI_STATE_DISABLED
|
||||
je .quit
|
||||
|
||||
; 1. Test de collision (Hit Test)
|
||||
; X >= Widget.X ?
|
||||
cmp cx, [si + widget.x]
|
||||
cmp cx, [gs:si + widget.x]
|
||||
jl .no_hit
|
||||
|
||||
; X <= Widget.X + Widget.W ?
|
||||
mov di, [si + widget.x]
|
||||
add di, [si + widget.w]
|
||||
mov di, [gs:si + widget.x]
|
||||
add di, [gs:si + widget.w]
|
||||
cmp cx, di
|
||||
jg .no_hit
|
||||
|
||||
; Y >= Widget.Y ?
|
||||
cmp dx, [si + widget.y]
|
||||
cmp dx, [gs:si + widget.y]
|
||||
jl .no_hit
|
||||
|
||||
; Y <= Widget.Y + Widget.H ?
|
||||
mov di, [si + widget.y]
|
||||
add di, [si + widget.h]
|
||||
mov di, [gs:si + widget.y]
|
||||
add di, [gs:si + widget.h]
|
||||
cmp dx, di
|
||||
jg .no_hit
|
||||
|
||||
|
|
@ -513,27 +548,27 @@ gui_update_button:
|
|||
jz .hovering
|
||||
|
||||
; -> Clic maintenu
|
||||
mov byte [si + widget.state], GUI_STATE_PRESSED
|
||||
mov byte [gs:si + widget.state], GUI_STATE_PRESSED
|
||||
jmp .draw_update
|
||||
|
||||
.hovering:
|
||||
; Souris dessus, mais pas de clic
|
||||
; Si on était en PRESSED juste avant, c'est un "CLICK" valide (Relâchement)
|
||||
cmp byte [si + widget.state], GUI_STATE_PRESSED
|
||||
cmp byte [gs:si + widget.state], GUI_STATE_PRESSED
|
||||
jne .just_hover
|
||||
|
||||
; C'est un click valide !
|
||||
mov al, 1 ; Return CLICKED
|
||||
mov byte [si + widget.state], GUI_STATE_HOVER
|
||||
mov byte [gs:si + widget.state], GUI_STATE_HOVER
|
||||
jmp .draw_update
|
||||
|
||||
.just_hover:
|
||||
mov byte [si + widget.state], GUI_STATE_HOVER
|
||||
mov byte [gs:si + widget.state], GUI_STATE_HOVER
|
||||
jmp .draw_update
|
||||
|
||||
.no_hit:
|
||||
; Souris en dehors
|
||||
mov byte [si + widget.state], GUI_STATE_NORMAL
|
||||
mov byte [gs:si + widget.state], GUI_STATE_NORMAL
|
||||
|
||||
.draw_update:
|
||||
; Appelle la fonction de dessin pour mettre à jour le visuel
|
||||
|
|
|
|||
Loading…
Reference in a new issue