From 1669788929276125133fa6ded675368d3826e897 Mon Sep 17 00:00:00 2001 From: Frater <13979047+saintfrater@users.noreply.github.com> Date: Thu, 5 Feb 2026 20:41:11 +0100 Subject: [PATCH] checkboxes & read-me update --- doc/assets/Capture-2026-02-05-203804.png | Bin 0 -> 24715 bytes readme.md | 10 ++ src/boot.asm | 52 ++++++-- src/services/gui_lib.asm | 146 +++++++++++++++++++++-- 4 files changed, 187 insertions(+), 21 deletions(-) create mode 100644 doc/assets/Capture-2026-02-05-203804.png diff --git a/doc/assets/Capture-2026-02-05-203804.png b/doc/assets/Capture-2026-02-05-203804.png new file mode 100644 index 0000000000000000000000000000000000000000..8bf076b0db4d5a020ec9106b284e22de14e4631b GIT binary patch literal 24715 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", 0 ; ----------------------------------------------------------- diff --git a/src/services/gui_lib.asm b/src/services/gui_lib.asm index 3aaf471..531a813 100644 --- a/src/services/gui_lib.asm +++ b/src/services/gui_lib.asm @@ -20,10 +20,13 @@ ; ; ============================================================================= -; --- Configuration Mémoire --- +; --- Configuration --- %define GUI_RAM_SEG 0x0A00 ; Segment de données UI %define GUI_MAX_WIDGETS 32 ; Nombre max de widgets simultanés +; Dimensions +%define GUI_CHECKBOX_SIZE 10 ; + ; --- Drapeaux & États --- %define GUI_STATE_FREE 0 ; Le slot est vide (mémoire dispo) %define GUI_STATE_NORMAL 1 ; Affiché, repos @@ -36,6 +39,7 @@ %define WIDGET_TYPE_SLIDER 1 %define WIDGET_TYPE_LABEL 2 %define WIDGET_TYPE_ROUND_BUTTON 3 +%define WIDGET_TYPE_CHECKBOX 4 ; --- Widgets attributs --- %define BUTTON_OK 1 @@ -307,6 +311,11 @@ gui_update_logic: jmp .done .case_4: + cmp byte [gs:si + widget.type], WIDGET_TYPE_CHECKBOX + jne .case_5 + call gui_logic_checkbox + + .case_5: jmp .done .miss: ; Si on n'est plus dessus, mais qu'on l'était avant (HOVER/PRESSED), il faut redessiner ! @@ -434,6 +443,33 @@ gui_logic_slider: xor ax, ax ret +; --- Logique spécifique Checkbox --- +gui_logic_checkbox: + test bl, 1 ; Clic gauche ? + jz .released + + ; Clic enfoncé + mov byte [gs:si + widget.state], GUI_STATE_PRESSED + xor ax, ax + ret + + .released: + cmp byte [gs:si + widget.state], GUI_STATE_PRESSED + jne .hover + + ; Clic validé ! Toggle value + xor word [gs:si + widget.attr_val], 1 + mov byte [gs:si + widget.oldstate], 255 ; Force redraw + + mov al, 1 + mov byte [gs:si + widget.state], GUI_STATE_HOVER + ret + + .hover: + mov byte [gs:si + widget.state], GUI_STATE_HOVER + xor ax, ax + ret + ; Dessine le widget pointé par SI @@ -478,9 +514,15 @@ gui_draw_single_widget: cmp byte [gs:si + widget.type], WIDGET_TYPE_ROUND_BUTTON jne .case_4 call draw_round_button -; jmp .done + jmp .done .case_4: + cmp byte [gs:si + widget.type], WIDGET_TYPE_CHECKBOX + jne .case_5 + call draw_checkbox + jmp .done + + .case_5: @@ -612,22 +654,23 @@ draw_round_button: .paint_normal: GFX RECTANGLE_FILL, ax, bx, cx, dx, PATTERN_WHITE mov di, 0 ; Couleur Noire - call .draw_round_borders + call draw_round_borders GFX TXT_MODE, GFX_TXT_BLACK_TRANSPARENT jmp .draw_text_now .paint_hover: GFX RECTANGLE_FILL, ax, bx, cx, dx, PATTERN_WHITE + GFX RECTANGLE_ROUND, ax, bx, cx, dx, 0 + ; GFX RECTANGLE_FILL, ax, bx, cx, dx, PATTERN_WHITE_LIGHT mov di, 0 ; Couleur Noire - GFX RECTANGLE_FILL, ax, bx, cx, dx, PATTERN_WHITE_LIGHT - call .draw_round_borders + call draw_round_borders GFX TXT_MODE, GFX_TXT_BLACK_TRANSPARENT jmp .draw_text_now .paint_pressed: GFX RECTANGLE_FILL, ax, bx, cx, dx, PATTERN_BLACK mov di, 1 ; Bordure Blanche sur fond noir - call .draw_round_borders + call draw_round_borders GFX TXT_MODE, GFX_TXT_WHITE_TRANSPARENT jmp .draw_text_now @@ -641,9 +684,8 @@ draw_round_button: .done: ret -.draw_round_borders: +draw_round_borders: ; Bordure principale - GFX RECTANGLE_ROUND, ax, bx, cx, dx, di ; Si style "OK" (attr_mode & BUTTON_OK), on ajoute la double bordure ;test byte [gs:si + widget.attr_mode], BUTTON_OK ;jz .done_borders @@ -655,6 +697,93 @@ draw_round_button: .done_borders: ret +draw_checkbox: + ; met un "fond" blanc + GFX RECTANGLE_FILL, ax, bx, cx, dx, PATTERN_WHITE + + cmp byte [gs:si + widget.state], GUI_STATE_HOVER + jne .no_hover + GFX RECTANGLE_ROUND, ax, bx, cx, dx, 0 + .no_hover: + + ; Calcul coords box (centré verticalement) + mov ax, [gs:si + widget.x] + add ax, 4 + mov bx, [gs:si + widget.y] + + mov cx, [gs:si + widget.h] + mov dx, [gs:si + widget.w] + + sub cx, GUI_CHECKBOX_SIZE + shr cx, 1 + add bx, cx ; Y1 + + mov cx, ax + add cx, GUI_CHECKBOX_SIZE ; X2 + + mov dx, bx + add dx, GUI_CHECKBOX_SIZE ; Y2 + + ; Sauvegarde coords pour le X + push ax + push bx + push cx + push dx + + ; Fond blanc + Bordure noire + GFX RECTANGLE_FILL, ax, bx, cx, dx, PATTERN_WHITE + GFX RECTANGLE, ax, bx, cx, dx, 0 + + ; Check if checked + cmp word [gs:si + widget.attr_val], 0 + je .draw_label + + ; Dessin du X (Diagonales) + add ax, 2 + add bx, 2 + sub cx, 2 + sub dx, 2 + + push ax + push bx + push dx + .loop_x: + cmp ax, cx + jg .end_x + GFX PUTPIXEL, ax, bx, 0 + GFX PUTPIXEL, ax, dx, 0 + inc ax + inc bx + dec dx + jmp .loop_x + .end_x: + pop dx + pop bx + pop ax + + .draw_label: + pop dx + pop cx + pop bx + pop ax + + ; Dessin du texte à droite (BoxX2 + 6) + add cx, 6 + + ; Y = Centré par rapport au widget + mov bx, [gs:si + widget.y] + mov ax, [gs:si + widget.h] + sub ax, 8 + shr ax, 1 + add bx, ax + inc bx + + GFX GOTOXY, cx, bx + mov dx, [gs:si + widget.text_seg] + mov ax, [gs:si + widget.text_ofs] + GFX WRITE, dx, ax + + ret ; ; affiche le texte au centre du widget gs:si ; @@ -691,6 +820,7 @@ draw_text: sub bx, 8 shr bx, 1 add bx, [gs:si + widget.y] ; Y final + inc bx pop cx ; CX = X Final, BX = Y Final