fox32rom/menu.asm

288 lines
8.5 KiB
NASM

; menu routines
const MENU_SELECTED_BACKGROUND_COLOR: 0xFFFFFFFF
const MENU_SELECTED_TEXT_COLOR: 0xFF000000
const MENU_UNSELECTED_BACKGROUND_COLOR: 0xFF3F3F3F
const MENU_UNSELECTED_TEXT_COLOR: 0xFFFFFFFF
; draw menu items
; inputs:
; r0: pointer to menu bar root struct
; r1: selected root menu item
; r2: hovering menu item (or 0xFFFFFFFF for none)
; outputs:
; none
draw_menu_items:
push r0
push r1
push r2
push r3
push r4
push r5
push r6
push r7
push r8
push r29
push r30
push r31
; calculate the X position of the menu
mov r31, r1 ; load number of the selected item into r31 for looping
mov r30, 16 ; X counter
cmp r31, 0 ; we don't need to loop if this is menu 0
ifz jmp draw_menu_items_calculate_x_skip
mov r4, r0
add r4, 5 ; point to start of root menu items text pointer
draw_menu_items_calculate_x_loop:
mov r3, [r4] ; get pointer to text
movz.8 r3, [r3] ; get text length byte
add r3, 2 ; add 2 for the spaces on each side of the text
mul r3, 8 ; characters are 8 pixels wide
add r30, r3 ; add length to X counter
add r4, 8 ; point to next text pointer
loop draw_menu_items_calculate_x_loop
draw_menu_items_calculate_x_skip:
sub r30, 8 ; move the menu to the left by 8 pixels
mov.16 [MENU_POSITION_X], r30
mov r31, r0
inc r31 ; point to menu list pointer
mul r1, 8 ; point to the selected menu
add r31, r1
mov r0, [r31] ; load menu list pointer
movz.8 r31, [r0] ; load number of menu items
mov r30, r2 ; r30: number of the hovered item
mov r29, 0 ; counter of how many menu items drawn so far
; calculate the required height for the menu overlay
; multiply the number of menu items by 16 (the font is 16 pixels tall)
mov r1, r31
mul r1, 16
mov.16 [MENU_HEIGHT], r1
; calculate the required width for the menu overlay
; multiply the width by 8 (the font is 8 pixels wide)
mov r1, r0
inc r1
movz.8 r1, [r1] ; load width of menu
mov r8, r1 ; save the width in characters in r8 for later
mul r1, 8
mov.16 [MENU_WIDTH], r1
push r0
; set properties of overlay 29
mov.16 [MENU_POSITION_Y], 16
mov [MENU_FRAMEBUFFER_PTR], MENU_FRAMEBUFFER
mov r0, 0x8000001D ; overlay 29: position
mov.16 r1, [MENU_POSITION_Y]
sla r1, 16
mov.16 r1, [MENU_POSITION_X]
out r0, r1
mov r0, 0x8000011D ; overlay 29: size
mov.16 r1, [MENU_HEIGHT]
sla r1, 16
mov.16 r1, [MENU_WIDTH]
out r0, r1
mov r0, 0x8000021D ; overlay 29: framebuffer pointer
mov r1, [MENU_FRAMEBUFFER_PTR]
out r0, r1
mov r0, 0x8000031D
out r0, 1
; draw empty menu
mov r6, r31 ; outer loop counter
movz.8 r0, ' '
mov r1, 0
mov r2, 0
mov r5, 29
draw_empty_menu_loop:
mov r7, r8 ; inner loop counter
cmp r30, r29
;ifz mov r3, MENU_UNSELECTED_BACKGROUND_COLOR
ifz mov r4, MENU_SELECTED_BACKGROUND_COLOR
;ifnz mov r3, MENU_SELECTED_BACKGROUND_COLOR
ifnz mov r4, MENU_UNSELECTED_BACKGROUND_COLOR
draw_empty_menu_line_loop:
call draw_font_tile_to_overlay
add r1, 8
dec r7
ifnz jmp draw_empty_menu_line_loop
mov r1, 0
add r2, 16
inc r29
dec r6
ifnz jmp draw_empty_menu_loop
mov r29, 0 ; counter of how many menu items drawn so far
pop r0
; draw menu text
add r0, 3 ; point to start of menu items text
mov r2, 0 ; Y = 0
draw_menu_text_loop:
cmp r30, r29
ifz mov r3, MENU_SELECTED_TEXT_COLOR
ifz mov r4, MENU_SELECTED_BACKGROUND_COLOR
ifnz mov r3, MENU_UNSELECTED_TEXT_COLOR
ifnz mov r4, MENU_UNSELECTED_BACKGROUND_COLOR
mov r1, 0 ; X = 0
call draw_str_to_overlay ; draw menu item text
mov r1, r0
dec r1 ; point to length byte of this menu item
movz.8 r1, [r1] ; load length byte
inc r1 ; add one to count the null-terminator
add r0, r1 ; add length to menu item text pointer
inc r0 ; increment past length byte
add r2, 16 ; add 16 to Y
inc r29
loop draw_menu_text_loop
pop r31
pop r30
pop r29
pop r8
pop r7
pop r6
pop r5
pop r4
pop r3
pop r2
pop r1
pop r0
ret
; hide the menu
; inputs:
; r0: pointer to menu bar root struct
; outputs:
; none
close_menu:
push r1
; disable overlay 29
mov r1, 0x8000031D
out r1, 0
mov r1, 0xFFFFFFFF
call draw_menu_bar_root_items
pop r1
ret
; update the currently open menu
; detects mouse movements over the menu and handles clicks
; this should only be called if a event_type_menu_update event is received
; inputs:
; *** these inputs should already be in the required registers from the event parameters ***
; r1: pointer to menu bar root struct
; r2: selected root menu item
; r3: hovering menu item (or 0xFFFFFFFF for none)
; outputs:
; none
; the event is added back into the event queue if the menu is still open
menu_update_event:
push r0
push r1
push r2
push r3
push r4
push r5
push r6
push r7
push r8
push r9
mov r8, r1 ; r8: pointer to menu bar root struct
mov r9, r2 ; r9: selected root menu item
mov r10, r3 ; r10: hovering menu item (or 0xFFFFFFFF for none)
; check if the menu overlay is enabled
; if the menu was closed then exit without readding the update event to the event queue
in r0, 0x8000031D
cmp r0, 0
ifz jmp menu_update_event_end_no_add
; get the current mouse position and check if the menu overlay covers that position
; if the mouse is not in the menu, then there is nothing to do
call get_mouse_position
mov r2, 29
call check_if_enabled_overlay_covers_position
ifnz jmp menu_update_event_end_add
; make the mouse position relative to the menu overlay
mov r2, 29
call make_coordinates_relative_to_overlay
; if the currently hovered item is different than the hovered item in the event parameters,
; then redraw the menu with correct hovered item
div r1, 16 ; mouse Y / 16
cmp r1, r10 ; compare the currently hovered item to the hovered item in event parameter 2
ifz jmp menu_update_event_no_redraw
mov r10, r1 ; set the hovering item to the currently hovering item
mov r2, r1
mov r1, r9
mov r0, r8
call draw_menu_items
menu_update_event_no_redraw:
; check the mouse held bit
; this is kinda hacky but it works
call get_mouse_button
bts r0, 2
ifnz jmp menu_update_event_clicked
jmp menu_update_event_end_add
menu_update_event_clicked:
; wait until the mouse button is released
; this is extremely hacky
call get_mouse_button
bts r0, 2
ifnz jmp menu_update_event_clicked
; add an EVENT_TYPE_MENU_CLICK event
mov r1, r8 ; event parameter 0: pointer to menu bar root struct
mov r2, r9 ; event parameter 1: selected root menu item
mov r3, r10 ; event parameter 2: selected menu item
mov r4, 0
mov r5, 0
mov r6, 0
mov r7, 0
mov r0, EVENT_TYPE_MENU_CLICK
call new_event
; add an EVENT_TYPE_MENU_ACK event
mov r1, 0
mov r2, 0
mov r3, 0
mov r4, 0
mov r5, 0
mov r6, 0
mov r7, 0
mov r0, EVENT_TYPE_MENU_ACK
call new_event
jmp menu_update_event_end_no_add
menu_update_event_end_add:
; readd the event_type_menu_update event to the event queue
mov r1, r8 ; event parameter 0: pointer to menu bar root struct
mov r2, r9 ; event parameter 1: selected root menu item
mov r3, r10 ; event parameter 2: hovering menu item (or 0xFFFFFFFF for none)
mov r4, 0
mov r5, 0
mov r6, 0
mov r7, 0
mov r0, EVENT_TYPE_MENU_UPDATE
call new_event
menu_update_event_end_no_add:
pop r9
pop r8
pop r7
pop r6
pop r5
pop r4
pop r3
pop r2
pop r1
pop r0
ret