package main import rl "vendor:raylib" import "core:math/ease" import "core:fmt" 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: ^Tween, 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 { tween_cancel(list.tween) } list.tween = tween_to( &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 }