128 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Odin
		
	
	
	
	
	
			
		
		
	
	
			128 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Odin
		
	
	
	
	
	
| package main
 | |
| 
 | |
| import "core:fmt"
 | |
| import "core:math/ease"
 | |
| import "ntween"
 | |
| import rl "vendor:raylib"
 | |
| 
 | |
| MenuItemType :: enum {
 | |
| 	NONE,
 | |
| 	BOOL,
 | |
| 	INT,
 | |
| }
 | |
| 
 | |
| BoolStrings := map[bool]cstring {
 | |
| 	true  = "вкл",
 | |
| 	false = "выкл",
 | |
| }
 | |
| 
 | |
| MenuItem :: struct {
 | |
| 	text:  cstring,
 | |
| 	param: rawptr,
 | |
| 	type:  MenuItemType,
 | |
| }
 | |
| 
 | |
| MenuList :: struct($T: typeid) {
 | |
| 	state:          ^GameState,
 | |
| 	position:       vec2,
 | |
| 	line_size:      f32,
 | |
| 	font_size:      f32,
 | |
| 	active_element: T,
 | |
| 	active_marker:  vec2,
 | |
| 	tween:          ^ntween.Tween(f32),
 | |
| 	elements:       ^[T]MenuItem,
 | |
| 	menu_pressed:   proc(state: ^GameState, element: T),
 | |
| 	background:     rl.Color,
 | |
| 	mouse_pos:      vec2,
 | |
| }
 | |
| 
 | |
| 
 | |
| menu_list_update :: proc(list: ^MenuList($T)) {
 | |
| 
 | |
| 	activate_element := false
 | |
| 	prev_element := cast(i8)list.active_element
 | |
| 	cur_element := prev_element
 | |
| 
 | |
| 	last_mouse_pos := list.mouse_pos
 | |
| 	list.mouse_pos = rl.GetMousePosition()
 | |
| 
 | |
| 	size := menu_list_get_size(list)
 | |
| 	if rl.CheckCollisionPointRec(
 | |
| 		list.mouse_pos,
 | |
| 		rl.Rectangle{x = list.position.x, y = list.position.y, width = size.x, height = size.y},
 | |
| 	) {
 | |
| 		if last_mouse_pos != list.mouse_pos {
 | |
| 			mouse_relative := list.mouse_pos - list.position
 | |
| 			cur_element = i8(mouse_relative.y / list.line_size)
 | |
| 		}
 | |
| 		if rl.IsMouseButtonPressed(rl.MouseButton.LEFT) {
 | |
| 			list.menu_pressed(list.state, list.active_element)
 | |
| 		}
 | |
| 	}
 | |
| 	last_mouse_pos = list.mouse_pos
 | |
| 
 | |
| 
 | |
| 	if rl.IsKeyPressed(rl.KeyboardKey.DOWN) {
 | |
| 		cur_element += 1
 | |
| 	}
 | |
| 	if rl.IsKeyPressed(rl.KeyboardKey.UP) {
 | |
| 		cur_element -= 1
 | |
| 	}
 | |
| 	if prev_element != cur_element {
 | |
| 		if cur_element < 0 {cur_element = len(T) - 1}
 | |
| 		if cur_element == len(T) {cur_element = 0}
 | |
| 		list.active_element = cast(T)cur_element
 | |
| 		if list.tween != nil {
 | |
| 			ntween.cancel(list.tween)
 | |
| 		}
 | |
| 		list.tween = ntween.animate(
 | |
| 			&f32_tweens,
 | |
| 			&list.active_marker.y,
 | |
| 			f32(list.active_element) * list.line_size,
 | |
| 			0.25,
 | |
| 			ease.Ease.Quadratic_Out,
 | |
| 		)
 | |
| 	}
 | |
| 	if rl.IsKeyPressed(rl.KeyboardKey.ENTER) || rl.IsKeyPressed(rl.KeyboardKey.SPACE) {
 | |
| 		list.menu_pressed(list.state, list.active_element)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| menu_list_draw :: proc(list: ^MenuList($T)) {
 | |
| 	if list.background[3] != 0 {
 | |
| 		size := menu_list_get_size(list)
 | |
| 		rl.DrawRectangleV(list.position - {40, 40}, size + {80, 80}, list.background)
 | |
| 	}
 | |
| 	rl.DrawTextEx(
 | |
| 		Res.Fonts.UI,
 | |
| 		">",
 | |
| 		list.position + list.active_marker + {-30, 0},
 | |
| 		48,
 | |
| 		2,
 | |
| 		rl.WHITE,
 | |
| 	)
 | |
| 	for el, i in list.elements {
 | |
| 		pos := list.position + {0, f32(i) * list.line_size}
 | |
| 		text := el.text
 | |
| 		if el.type == .BOOL {
 | |
| 			param := transmute(^bool)el.param
 | |
| 			value := param^
 | |
| 			text = rl.TextFormat("%s: %s", el.text, BoolStrings[value])
 | |
| 		}
 | |
| 		rl.DrawTextEx(Res.Fonts.UI, text, pos, list.font_size, 2, rl.WHITE)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| menu_list_get_size :: proc(list: ^MenuList($T)) -> vec2 {
 | |
| 	size := vec2{}
 | |
| 	for el, i in list.elements {
 | |
| 		line_size := rl.MeasureTextEx(Res.Fonts.UI, el.text, list.font_size, 2)
 | |
| 		if line_size.x > size.x {
 | |
| 			size.x = line_size.x
 | |
| 		}
 | |
| 		size.y += list.line_size
 | |
| 	}
 | |
| 	return size
 | |
| }
 |