kernel: Add a very basic GUI widget system

This commit is contained in:
Ry 2022-12-27 18:01:55 -08:00
parent 5c1a000e24
commit 8ac2d2c0d4
7 changed files with 316 additions and 2 deletions

View File

@ -7,6 +7,7 @@
mov r4, 32
mov r5, 32
mov r6, 0
mov r7, 0
call new_window
call get_unused_task_id
@ -85,7 +86,7 @@ close_window:
jmp event_loop_end
window_title: data.str "Terminal" data.8 0
window_struct: data.fill 0, 32
window_struct: data.fill 0, 36
shell_task_id: data.8 0

View File

@ -38,3 +38,13 @@ write: jmp [0x00000D20]
; shell jump table
new_shell_task: jmp [0x00000E10]
; widget jump table
draw_widgets_to_window: jmp [0x00000F10]
handle_widget_click: jmp [0x00000F14]
; event types
const EVENT_TYPE_BUTTON_CLICK: 0x80000000
; widget types
const WIDGET_TYPE_BUTTON: 0x00000000

View File

@ -56,6 +56,11 @@ jump_table:
; shell jump table
org.pad 0x00000610
data.32 new_shell_task
; widget jump table
org.pad 0x00000710
data.32 draw_widgets_to_window
data.32 handle_widget_click
jump_table_end:
; initialization code
@ -265,6 +270,7 @@ get_os_version:
#include "fxf/fxf.asm"
#include "shell/shell.asm"
#include "task.asm"
#include "widget/widget.asm"
#include "window/window.asm"
#include "vfs.asm"

95
kernel/widget/button.asm Normal file
View File

@ -0,0 +1,95 @@
; button widget routines
; button widget struct:
; data.32 next_ptr - pointer to next widget, or 0 for none
; data.32 id - the ID number of this widget
; data.32 type - the type of this widget
; data.32 text_ptr - pointer to null-terminated text string
; data.32 foreground_color - text foreground color
; data.32 background_color - button background color
; data.16 width - width of this button
; data.16 reserved
; data.16 x_pos - X coordinate of this widget
; data.16 y_pos - Y coordinate of this widget
const BUTTON_WIDGET_STRUCT_SIZE: 32 ; 8 words = 32 bytes
; draw a button widget to a window
; FIXME: this needs some major cleanup, this is like register soup
; inputs:
; r0: pointer to window struct
; r1: pointer to a null-terminated string
; r2: foreground color
; r3: background color
; r4: button width
; r5: X coordinate
; r6: Y coordinate
draw_button_widget:
push r0
push r1
push r2
push r3
push r4
push r5
push r10
push r20
push r30
push r31
push r1
mov r20, 0
draw_button_widget_strlen_loop:
inc r1
inc r20
cmp.8 [r1], 0
ifnz jmp draw_button_widget_strlen_loop
pop r1
mov r30, r5
mov r31, r4
div r4, 2
mul r20, 8
div r20, 2
sub r4, r20
add r5, r4
call get_window_overlay_number
mov r10, r0
push r1
push r2
push r3
push r4
push r5
mov r5, r0
mov r2, r31
mov r4, r3
mov r3, 16
mov r0, r30
mov r1, r6
call draw_filled_rectangle_to_overlay
pop r5
pop r4
pop r3
pop r2
pop r1
mov r0, r1
mov r4, r3
mov r3, r2
mov r1, r5
mov r2, r6
mov r5, r10
call draw_str_to_overlay
pop r31
pop r30
pop r20
pop r10
pop r5
pop r4
pop r3
pop r2
pop r1
pop r0
ret

194
kernel/widget/widget.asm Normal file
View File

@ -0,0 +1,194 @@
; widget management routines
; widget types
const WIDGET_TYPE_BUTTON: 0x00000000
; widget struct:
; data.32 next_ptr - pointer to next widget, or 0 for none
; data.32 id - the ID number of this widget
; data.32 type - the type of this widget
; remaining entries vary depending on widget type
; draw all of a window's widgets to a window
; inputs:
; r0: pointer to window struct
; outputs:
; none
draw_widgets_to_window:
push r10
; get pointer to first widget
mov r10, r0
add r10, 32
mov r10, [r10]
draw_widgets_to_window_next:
; check widget type
add r10, 8
cmp [r10], WIDGET_TYPE_BUTTON
ifz call draw_widgets_to_window_button
; point to the next widget, if any
sub r10, 8
mov r10, [r10]
cmp r10, 0
ifz jmp draw_widgets_to_window_done
jmp draw_widgets_to_window_next
draw_widgets_to_window_done:
pop r10
ret
draw_widgets_to_window_button:
push r1
push r2
push r3
push r4
push r5
push r6
push r10
; put button parameters in registers for the drawing routine
add r10, 4
mov r1, [r10] ; text_ptr
add r10, 4
mov r2, [r10] ; foreground_color
add r10, 4
mov r3, [r10] ; background_color
add r10, 4
movz.16 r4, [r10] ; width
add r10, 4
movz.16 r5, [r10] ; x_pos
add r10, 2
movz.16 r6, [r10] ; y_pos
call draw_button_widget
pop r10
pop r6
pop r5
pop r4
pop r3
pop r2
pop r1
ret
; check if a widget was clicked and if so, add an event to the window's event queue
; inputs:
; r0: pointer to window struct
; r1: X coordinate of click
; r2: Y coordinate of click
; outputs:
; none
handle_widget_click:
push r0
push r1
push r2
push r3
push r4
push r5
push r6
push r7
push r8
push r30
mov r30, r0
; get pointer to first widget
add r0, 32
mov r0, [r0]
handle_widget_click_check_type:
; check widget type
add r0, 8
cmp [r0], WIDGET_TYPE_BUTTON
ifz jmp handle_widget_click_button
handle_widget_click_done:
pop r30
pop r8
pop r7
pop r6
pop r5
pop r4
pop r3
pop r2
pop r1
pop r0
ret
handle_widget_click_button:
push r0
push r10
push r11
push r12
push r21
push r22
; get button width
add r0, 16
movz.16 r10, [r0]
; get button X coordinate
add r0, 4
movz.16 r11, [r0]
; get button Y coordinate
add r0, 2
movz.16 r12, [r0]
; calculate button's right side coordinate
mov r21, r11
add r21, r10
; calculate button's bottom right corner coordinate
mov r22, r12
add r22, 16
; check if r1 is between r11 and r21
; and if r2 is between r12 and r22
cmp r1, r11
iflt jmp handle_widget_click_button_no_click
cmp r1, r21
ifgt jmp handle_widget_click_button_no_click
cmp r2, r12
iflt jmp handle_widget_click_button_no_click
cmp r2, r22
ifgt jmp handle_widget_click_button_no_click
; if we reach this point then the button was clicked!!
pop r22
pop r21
pop r12
pop r11
pop r10
pop r0
; add a button click event to the window
sub r0, 4
mov r1, [r0] ; parameter 0: widget ID
mov r2, 0
mov r3, 0
mov r4, 0
mov r5, 0
mov r6, 0
mov r7, 0
mov r8, r30
mov r0, EVENT_TYPE_BUTTON_CLICK
call new_window_event
jmp handle_widget_click_done
handle_widget_click_button_no_click:
pop r22
pop r21
pop r12
pop r11
pop r10
pop r0
; get pointer to next widget
sub r0, 8
mov r0, [r0]
; if this is the last widget, then exit
cmp r0, 0
ifz jmp handle_widget_click_done
; retry
jmp handle_widget_click_check_type
; include widget types
#include "widget/button.asm"

View File

@ -1,5 +1,8 @@
; window event routines
; event types
const EVENT_TYPE_BUTTON_CLICK: 0x80000000
const WINDOW_EVENT_SIZE: 32
; get the next window event and remove it from the event queue

View File

@ -13,8 +13,9 @@
; data.8 reserved_1
; data.16 reserved_2
; data.32 menu_bar_ptr - pointer to this window's menu bar root struct, or 0 for none
; data.32 first_widget_ptr - pointer to this window's first widget
const WINDOW_STRUCT_SIZE: 32 ; 8 words = 32 bytes
const WINDOW_STRUCT_SIZE: 36 ; 9 words = 36 bytes
const TITLE_BAR_HEIGHT: 16
; create a new window and allocate memory as required
@ -26,6 +27,7 @@ const TITLE_BAR_HEIGHT: 16
; r4: initial X coordinate (top left corner of title bar)
; r5: initial Y coordinate (top left corner of title bar)
; r6: pointer to menu bar root struct, or 0x00000000 for no menu bar
; r7: pointer to first widget, or 0x00000000 for no widgets
; outputs:
; none
new_window:
@ -57,6 +59,9 @@ new_window:
; menu bar root struct pointer
add r10, 6
mov [r10], r6
; first widget pointer
add r10, 4
mov [r10], r7
; then, allocate memory for the framebuffer
; the space required is width * (height + TITLE_BAR_HEIGHT) * 4