package window import "core:container/queue" import "core:fmt" Window :: struct { title: string, width, height: u16, focused: bool, backend: Backend_Info, event_queue: Event_Queue, } Event_Queue :: queue.Queue(Event) Event :: union { Event_Quit, Event_Focus, Event_Input, Event_Resize, } Event_Quit :: struct {} Event_Focus :: struct { is_focused: bool, } Event_Input_State :: enum { Up, Down, } Virtual_Key :: enum { Number_0, Number_1, Number_2, Number_3, Number_4, Number_5, Number_6, Number_7, Number_8, Number_9, Letter_A, Letter_B, Letter_C, Letter_D, Letter_E, Letter_F, Letter_G, Letter_H, Letter_I, Letter_J, Letter_K, Letter_L, Letter_M, Letter_N, Letter_O, Letter_P, Letter_Q, Letter_R, Letter_S, Letter_T, Letter_U, Letter_V, Letter_W, Letter_X, Letter_Y, Letter_Z, Space, Enter, Escape, Tab, Backspace, CapsLock, Shift, Control, Alt, Arrow_Up, Arrow_Down, Arrow_Left, Arrow_Right, Super, } Event_Keyboard :: struct { virtual_key: Virtual_Key, state: Event_Input_State, } Event_Mouse :: union { Event_Mouse_Move, Event_Mouse_Button, Event_Mouse_Delta, } Event_Mouse_Move :: struct { x, y: u16, } Mouse_Button :: enum { Left, Middle, Right } Event_Mouse_Button :: struct { button: Mouse_Button, state: Event_Input_State } Event_Mouse_Delta :: struct { x, y: i32, } Event_Input :: union { Event_Keyboard, Event_Mouse, // TODO: SS - Add 'Event_Gamepad'? } Event_Resize :: struct { new_width, new_height: u16, } create :: proc(width, height: u16) -> (^Window, bool) { assert(width > 0 && height > 0) w := new(Window) w.width = width w.height = height queue.init(&w.event_queue, 1024) when ODIN_OS == .Windows { if !init_window_windows(w) { free(w) return nil, false } } else { #assert(false, "Missing implementation for 'create'.") } set_title(w, "Window") // show_cursor(w, true) return w, true } set_title :: proc(window: ^Window, title: string) { assert(window != nil) window.title = title when ODIN_OS == .Windows { set_title_windows(window) } else { #assert(false, "Missing implementation for 'set_title'.") } } show_cursor :: proc(window: ^Window, show: bool) { when ODIN_OS == .Windows { show_cursor_window(window, show) } else { #assert(false, "Missing implementation for 'show_cursor'.") } } cursor_visible :: proc(window: ^Window) -> bool { when ODIN_OS == .Windows { return cursor_visible_windows(window) } else { #assert(false, "Missing implementation for 'cursor_visible'.") } return false } lock_cursor :: proc(window: ^Window, lock: bool) { when ODIN_OS == .Windows { lock_cursor_windows(window, lock) } show_cursor_window(window, !lock) } get_pointer_to_surface :: proc(window: ^Window) -> rawptr { when ODIN_OS == .Windows { return window.backend.hwnd } else { #assert(false, "Missing implementation for 'get_pointer_to_surface'.") } } poll :: proc(window: ^Window, out_event: ^Event) -> bool { assert(window != nil) assert(out_event != nil) when ODIN_OS == .Windows { update_windows(window) } else { #assert(false, "Missing implementation for 'update'.") } out_event^ = nil event, ok := queue.pop_front_safe(&window.event_queue) if !ok { return false } switch e in event { case Event_Quit: {} case Event_Focus: { window.focused = e.is_focused } case Event_Resize: { window.width = e.new_width window.height = e.new_height } case Event_Input: {} } assert(event != nil) out_event^ = event return true } destroy :: proc(window: ^Window) { assert(window != nil) when ODIN_OS == .Windows { destroy_windows(window) } else { #assert(false, "Missing implementation for 'destroy'.") } queue.destroy(&window.event_queue) free(window) }