sliders H & V

This commit is contained in:
Frater 2026-02-07 00:20:32 +01:00
commit ac89c58ddb
4 changed files with 360 additions and 93 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View file

@ -195,17 +195,30 @@ build_interface:
mov word [gs:si + widget.x], 10 mov word [gs:si + widget.x], 10
mov word [gs:si + widget.y], 100 mov word [gs:si + widget.y], 100
mov word [gs:si + widget.w], 150 mov word [gs:si + widget.w], 150
mov word [gs:si + widget.h], 20 mov word [gs:si + widget.h], 12
mov word [gs:si + widget.text_ofs], str_drag
mov word [gs:si + widget.text_seg], cs
mov byte [gs:si + widget.type], WIDGET_TYPE_SLIDER mov byte [gs:si + widget.type], WIDGET_TYPE_SLIDER
mov byte [gs:si + widget.attr_mode], 1 ; Horizontal mov byte [gs:si + widget.attr_mode], SLIDER_HORIZONTAL
mov word [gs:si + widget.attr_min], 10 ; X Min mov word [gs:si + widget.attr_min], 10 ; X Min
mov word [gs:si + widget.attr_max], 140 ; X Max (Widget.x + W - ThumbW) mov word [gs:si + widget.attr_max], 140 ; X Max (Widget.x + W - ThumbW)
mov word [gs:si + widget.attr_val], 10 ; Position initiale mov word [gs:si + widget.attr_val], 10 ; Position initiale
mov byte [gs:si + widget.thumb_pct], 15 ; Curseur fait 15% de la largeur mov byte [gs:si + widget.thumb_pct], 15 ; Curseur fait 15% de la largeur
; mov word [gs:si + widget.event_drag], on_drag_slider ; mov word [gs:si + widget.event_drag], on_drag_slider
; Créer Slider (Drag)
call gui_alloc_widget
jc .mem_full
mov word [gs:si + widget.x], 400
mov word [gs:si + widget.y], 10
mov word [gs:si + widget.w], 16
mov word [gs:si + widget.h], 150
mov byte [gs:si + widget.type], WIDGET_TYPE_SLIDER
mov byte [gs:si + widget.attr_mode], SLIDER_VERTICAL
mov word [gs:si + widget.attr_min], 10 ; X Min
mov word [gs:si + widget.attr_max], 140 ; X Max (Widget.x + W - ThumbW)
mov word [gs:si + widget.attr_val], 140 ; Position initiale
mov byte [gs:si + widget.thumb_pct], 25 ; Curseur fait 15% de la largeur
; mov word [gs:si + widget.event_drag], on_drag_slider
.mem_full: .mem_full:
ret ret
@ -216,7 +229,6 @@ str_hello db "Hello", 0
str_option1 db "option 1", 0 str_option1 db "option 1", 0
str_option2 db "option 2", 0 str_option2 db "option 2", 0
str_option3 db "option 3", 0 str_option3 db "option 3", 0
str_drag db "->", 0
; ----------------------------------------------------------- ; -----------------------------------------------------------
; timer ISR (IRQ -> INT) ; timer ISR (IRQ -> INT)

View file

@ -71,15 +71,13 @@
%define TXT_MODE 4 %define TXT_MODE 4
%define PUTCH 5 %define PUTCH 5
%define WRITE 6 %define WRITE 6
%define LINE_VERT 7 %define LINE 7
%define LINE_HORIZ 8 %define RECTANGLE 8
%define RECTANGLE 9 %define RECTANGLE_FILL 9
%define RECTANGLE_FILL 10 %define RECTANGLE_ROUND 10
%define RECTANGLE_ROUND 11 %define MOUSE_HIDE 11
%define MOUSE_HIDE 12 %define MOUSE_SHOW 12
%define MOUSE_SHOW 13 %define MOUSE_MOVE 13
%define MOUSE_MOVE 14
%define LINE 15
; ------------------------------------------------------------ ; ------------------------------------------------------------
; COMMENTAIRE SUR LA MÉTHODE D'APPEL ; COMMENTAIRE SUR LA MÉTHODE D'APPEL
@ -100,15 +98,14 @@ graph_driver:
dw cga_set_writemode ; mode texte dw cga_set_writemode ; mode texte
dw cga_putc ; dessin d'un caractère dw cga_putc ; dessin d'un caractère
dw cga_write ; dessin d'une chaine de caractère dw cga_write ; dessin d'une chaine de caractère
dw cga_line_vertical ; dessin d'une ligne verticale dw cga_line ; dessin d'une ligne (Bresenham) avec décision horizontale/verticale
dw cga_line_horizontal ; dessin d'une ligne horizontale
dw cga_draw_rect ; dessin d'un rectangle dw cga_draw_rect ; dessin d'un rectangle
dw cga_fill_rect ; dessin d'un rectangle plein dw cga_fill_rect ; dessin d'un rectangle plein
dw cga_draw_rounded_frame ; dessin d'un rectangle arrondi dw cga_draw_rounded_frame ; dessin d'un rectangle arrondi
dw cga_mouse_hide ; déplacement du curseur dw cga_mouse_hide ; déplacement du curseur
dw cga_mouse_show ; déplacement du curseur dw cga_mouse_show ; déplacement du curseur
dw cga_mouse_cursor_move ; déplacement du curseur dw cga_mouse_cursor_move ; déplacement du curseur
dw cga_line ; dessin d'une ligne (Bresenham)
; ============================================================================= ; =============================================================================
; SECTION : PATTERNS & FILL ; SECTION : PATTERNS & FILL
@ -790,6 +787,7 @@ cga_line_horizontal:
%undef .x1 %undef .x1
%undef .x2 %undef .x2
%undef .y %undef .y
; ------------------------------------------------------------ ; ------------------------------------------------------------
; cga_line (x1, y1, x2, y2, color) ; cga_line (x1, y1, x2, y2, color)
; Algorithme de Bresenham pour tracer une ligne arbitraire ; Algorithme de Bresenham pour tracer une ligne arbitraire
@ -803,6 +801,8 @@ cga_line_horizontal:
cga_line: cga_line:
push bp push bp
mov bp, sp mov bp, sp
pusha ; Sauvegarde de tous les registres (AX, BX, CX, DX, SI, DI)
push es ; Sauvegarde ES
; --- Optimisation : Lignes H/V --- ; --- Optimisation : Lignes H/V ---
mov ax, .y1 mov ax, .y1
@ -812,15 +812,24 @@ cga_line:
cmp ax, .x2 cmp ax, .x2
je .do_vert je .do_vert
sub sp, 10 ; Variables locales: dx, dy, sx, sy, err ; --- Bresenham ---
pusha
push es
mov ax, VIDEO_SEG mov ax, VIDEO_SEG
mov es, ax mov es, ax
call cga_mouse_hide 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 --- ; --- Initialisation Bresenham ---
; dx = abs(x2 - x1), sx = sign(x2 - x1) ; dx = abs(x2 - x1), sx = sign(x2 - x1)
mov ax, .x2 mov ax, .x2
@ -830,8 +839,8 @@ cga_line:
neg ax neg ax
neg bx ; sx = -1 neg bx ; sx = -1
.calc_dx: .calc_dx:
mov [bp-2], ax ; save dx mov .dx, ax ; save dx
mov [bp-6], bx ; save sx mov .sx, bx ; save sx
; dy = abs(y2 - y1), sy = sign(y2 - y1) ; dy = abs(y2 - y1), sy = sign(y2 - y1)
mov ax, .y2 mov ax, .y2
@ -841,13 +850,13 @@ cga_line:
neg ax neg ax
neg bx ; sy = -1 neg bx ; sy = -1
.calc_dy: .calc_dy:
mov [bp-4], ax ; save dy mov .dy, ax ; save dy
mov [bp-8], bx ; save sy mov .sy, bx ; save sy
; err = dx - dy ; err = dx - dy
mov ax, [bp-2] ; dx mov ax, .dx ; dx
sub ax, [bp-4] ; dy sub ax, .dy ; dy
mov [bp-10], ax ; err mov .err, ax ; err
; Coordonnées courantes ; Coordonnées courantes
mov cx, .x1 mov cx, .x1
@ -878,32 +887,30 @@ cga_line:
je .done je .done
.step: .step:
mov ax, [bp-10] ; e2 = err mov ax, .err ; e2 = err
shl ax, 1 ; e2 = 2*err shl ax, 1 ; e2 = 2*err
mov bx, [bp-4] ; dy mov bx, .dy ; dy
neg bx ; -dy neg bx ; -dy
cmp ax, bx cmp ax, bx
jle .check_y jle .check_y
add word [bp-10], bx ; err += -dy add .err, bx ; err += -dy
add cx, [bp-6] ; x += sx add cx, .sx ; x += sx
.check_y: .check_y:
mov bx, [bp-2] ; dx mov bx, .dx ; dx
cmp ax, bx cmp ax, bx
jge .loop ; if e2 >= dx, skip y step jge .loop ; if e2 >= dx, skip y step
add word [bp-10], bx ; err += dx add .err, bx ; err += dx
add dx, [bp-8] ; y += sy add dx, .sy ; y += sy
jmp .loop jmp .loop
.done: .done:
call cga_mouse_show call cga_mouse_show
pop es add sp, 10 ; Libération variables locales
popa jmp .exit
leave
ret
.do_horiz: .do_horiz:
push word [bp+12] ; color push word [bp+12] ; color
@ -912,8 +919,7 @@ cga_line:
push word [bp+4] ; x1 push word [bp+4] ; x1
call cga_line_horizontal call cga_line_horizontal
add sp, 8 add sp, 8
pop bp jmp .exit
ret
.do_vert: .do_vert:
push word [bp+12] ; color push word [bp+12] ; color
@ -922,13 +928,23 @@ cga_line:
push word [bp+4] ; x push word [bp+4] ; x
call cga_line_vertical call cga_line_vertical
add sp, 8 add sp, 8
.exit:
pop es
popa
pop bp pop bp
ret ret
%undef .x1 %undef .x1
%undef .y1 %undef .y1
%undef .x2 %undef .x2
%undef .y2 %undef .y2
%undef .color %undef .color
%undef .dx
%undef .dy
%undef .sx
%undef .sy
%undef .err
; ------------------------------------------------------------ ; ------------------------------------------------------------
; cga_draw_rect ; cga_draw_rect

View file

@ -20,6 +20,10 @@
; ;
; ============================================================================= ; =============================================================================
;
; https://github.com/buserror/libmui
;
; --- Configuration --- ; --- Configuration ---
%define GUI_RAM_SEG 0x0A00 ; 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 %define GUI_MAX_WIDGETS 32 ; Nombre max de widgets simultanés
@ -44,6 +48,9 @@
; --- Widgets attributs --- ; --- Widgets attributs ---
%define BUTTON_OK 1 %define BUTTON_OK 1
%define SLIDER_HORIZONTAL 1
%define SLIDER_VERTICAL 2
; --- Structure d'un OBJET (Bouton, etc) --- ; --- Structure d'un OBJET (Bouton, etc) ---
struc widget struc widget
.state resb 1 ; État (0=libre, >0=utilisé) .state resb 1 ; État (0=libre, >0=utilisé)
@ -371,55 +378,157 @@ gui_logic_slider:
mov byte [gs:si + widget.state], GUI_STATE_PRESSED 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 mov ax, cx
sub ax, [gs:si + widget.attr_val] sub ax, [gs:si + widget.attr_val]
mov [gs:si + widget.attr_anchor], ax mov [gs:si + widget.attr_anchor], ax
cmp byte [gs:si + widget.attr_mode], 2 jmp .init_done
jne .do_drag
.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 mov ax, dx
sub ax, [gs:si + widget.attr_val] sub ax, [gs:si + widget.attr_val]
mov [gs:si + widget.attr_anchor], ax 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: .do_drag:
; --- LOGIQUE DE DÉPLACEMENT --- ; --- 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 cmp byte [gs:si + widget.attr_mode], 1
je .drag_h je .drag_h
cmp byte [gs:si + widget.attr_mode], 2 cmp byte [gs:si + widget.attr_mode], 2
je .drag_v je .drag_v
pop dx
pop bx
pop ax
xor ax, ax xor ax, ax
ret ret
.drag_h: .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 mov ax, cx
sub ax, [gs:si + widget.attr_anchor] ; Nouvelle pos = MouseX - Anchor sub ax, [gs:si + widget.attr_anchor]
; Clamp Min jmp .apply_clamp
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
.drag_v: .drag_v:
mov ax, dx ; 1. Thumb Height -> AX
sub ax, [gs:si + widget.attr_anchor] mov ax, [gs:si + widget.h]
; Clamp Min mov bl, [gs:si + widget.thumb_pct]
cmp ax, [gs:si + widget.attr_min] mul bx
jge .chk_max_v mov bx, 100
mov ax, [gs:si + widget.attr_min] div bx ; AX = Thumb Height
.chk_max_v: ; 2. Max Pos = Y + H - ThumbHeight
; Clamp Max mov bx, [gs:si + widget.y]
cmp ax, [gs:si + widget.attr_max] add bx, [gs:si + widget.h]
jle .apply_pos sub bx, ax ; BX = Max Pos
mov ax, [gs:si + widget.attr_max]
; 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 jmp .apply_pos
.chk_max:
cmp ax, bx
jle .apply_pos
mov ax, bx
.apply_pos: .apply_pos:
pop dx
pop bx
add sp, 2 ; Clean AX from stack
cmp ax, [gs:si + widget.attr_val] cmp ax, [gs:si + widget.attr_val]
je .no_change je .no_change
mov [gs:si + widget.attr_val], ax mov [gs:si + widget.attr_val], ax
@ -471,7 +580,6 @@ gui_logic_checkbox:
ret ret
; Dessine le widget pointé par SI ; Dessine le widget pointé par SI
gui_draw_single_widget: gui_draw_single_widget:
pusha pusha
@ -525,23 +633,36 @@ gui_draw_single_widget:
.case_5: .case_5:
.done: .done:
GFX MOUSE_SHOW ; On réaffiche la souris APRES, capturant le widget fini GFX MOUSE_SHOW ; On réaffiche la souris APRES, capturant le widget fini
popa popa
ret 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: 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) ; 1. Dessiner la piste (Track)
GFX RECTANGLE_FILL, ax, bx, cx, dx, PATTERN_WHITE_LIGHT GFX RECTANGLE_FILL, .track_x1, .track_y1, .track_x2, .track_y2, PATTERN_WHITE_LIGHT
GFX RECTANGLE, ax, bx, cx, dx, 0 GFX RECTANGLE, .track_x1, .track_y1, .track_x2, .track_y2, 0
; 2. Calculer la taille du curseur (Thumb) ; 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 cmp byte [gs:si + widget.attr_mode], 2
je .calc_v je .calc_v
@ -553,12 +674,34 @@ draw_slider:
mov bx, 100 mov bx, 100
div bx ; AX = Thumb Width div bx ; AX = Thumb Width
mov bx, [gs:si + widget.y] ; BX = Y1 ; Thumb X1 = attr_val
mov dx, bx mov cx, [gs:si + widget.attr_val]
add dx, [gs:si + widget.h] ; DX = Y2
mov cx, [gs:si + widget.attr_val] ; CX = X1 ; --- CLAMP X1 (Fix Overflow) ---
add ax, cx ; AX = X1 + Width = X2 ; Max X1 = TrackX2 - ThumbW
xchg ax, cx ; AX = X1, CX = X2 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 jmp .draw_thumb
.calc_v: .calc_v:
@ -570,23 +713,119 @@ draw_slider:
mov bx, 100 mov bx, 100
div bx ; AX = Thumb Height div bx ; AX = Thumb Height
mov bx, [gs:si + widget.attr_val] ; BX = Y1 ; Thumb Y1 = attr_val
mov dx, bx mov cx, [gs:si + widget.attr_val]
add dx, ax ; DX = Y2
mov ax, [gs:si + widget.x] ; AX = X1 ; --- CLAMP Y1 (Fix Overflow) ---
mov cx, ax ; Max Y1 = TrackY2 - ThumbH
add cx, [gs:si + widget.w] ; CX = X2 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: .draw_thumb:
; 3. Dessiner le curseur (Thumb) ; 3. Dessiner le curseur (Thumb)
GFX RECTANGLE_FILL, ax, bx, cx, dx, PATTERN_WHITE GFX RECTANGLE_FILL, .thumb_x1, .thumb_y1, .thumb_x2, .thumb_y2, PATTERN_WHITE
GFX RECTANGLE, ax, bx, cx, dx, 0 GFX RECTANGLE, .thumb_x1, .thumb_y1, .thumb_x2, .thumb_y2, 0
add sp, 8 ; Nettoyer la pile des push ax..dx
GFX TXT_MODE, GFX_TXT_BLACK_TRANSPARENT ; --- Grip Lines (3 lignes pour un look moderne) ---
call draw_text 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 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: draw_button:
; Dispatch selon état ; Dispatch selon état