local Gui = require('gui') local math3d = require('math3d') local ctx = Gui.newContext() local input = Gui.newInputState() local function log_trace(fmt, ...) if not lua_debug or not fmt then return end print(string.format(fmt, ...)) end local buttonStates = { button1 = false, button2 = false, button3 = false, button4 = false } local statusMessage = 'Ready' local viewProjectionLogged = false local fpsMode = false local fpsToggleWasDown = false local fpsToggleKey = "F1" if type(config) == "table" then local bindings = config.input_bindings if type(bindings) == "table" then local key = bindings.fps_toggle or bindings.fps_toggle_key if type(key) == "string" or type(key) == "number" then fpsToggleKey = key end end end local function setFpsMode(enabled) fpsMode = enabled if window_set_relative_mouse_mode then window_set_relative_mouse_mode(enabled) end if window_set_mouse_grabbed then window_set_mouse_grabbed(enabled) end if window_set_cursor_visible then window_set_cursor_visible(not enabled) end statusMessage = enabled and "FPS mode enabled" or "FPS mode disabled" log_trace("FPS mode toggled: %s", enabled and "on" or "off") end local function updateFpsModeToggle() if not input_is_key_down then return end if fpsToggleKey == nil or fpsToggleKey == "" then return end local down = input_is_key_down(fpsToggleKey) if down and not fpsToggleWasDown then setFpsMode(not fpsMode) end fpsToggleWasDown = down if fpsMode and window_get_mouse_grabbed and not window_get_mouse_grabbed() then fpsMode = false statusMessage = "FPS mode disabled" end end local shader_variants = require("shader_variants").build_gui_variants() local function drawTestButtons() -- Background panel ctx:pushRect({x = 50, y = 50, width = 400, height = 400}, { color = {0.1, 0.1, 0.1, 0.9}, borderColor = {0.5, 0.5, 0.5, 1.0}, }) -- Title Gui.text(ctx, {x = 70, y = 70, width = 360, height = 40}, "2D Test Buttons", { fontSize = 28, alignX = "center", color = {1.0, 1.0, 1.0, 1.0}, }) -- Button 1 if Gui.button(ctx, "btn1", {x = 100, y = 130, width = 150, height = 50}, "Button 1") then buttonStates.button1 = not buttonStates.button1 statusMessage = "Button 1 " .. (buttonStates.button1 and "pressed" or "released") log_trace("Button 1 clicked: %s", statusMessage) end -- Button 2 if Gui.button(ctx, "btn2", {x = 270, y = 130, width = 150, height = 50}, "Button 2") then buttonStates.button2 = not buttonStates.button2 statusMessage = "Button 2 " .. (buttonStates.button2 and "pressed" or "released") log_trace("Button 2 clicked: %s", statusMessage) end -- Button 3 if Gui.button(ctx, "btn3", {x = 100, y = 200, width = 150, height = 50}, "Button 3") then buttonStates.button3 = not buttonStates.button3 statusMessage = "Button 3 " .. (buttonStates.button3 and "pressed" or "released") log_trace("Button 3 clicked: %s", statusMessage) end -- Button 4 if Gui.button(ctx, "btn4", {x = 270, y = 200, width = 150, height = 50}, "Button 4") then buttonStates.button4 = not buttonStates.button4 statusMessage = "Button 4 " .. (buttonStates.button4 and "pressed" or "released") log_trace("Button 4 clicked: %s", statusMessage) end -- Status display Gui.text(ctx, {x = 70, y = 280, width = 360, height = 30}, "Status: " .. statusMessage, { fontSize = 18, alignX = "center", color = {0.8, 0.8, 1.0, 1.0}, }) -- Button states display local statesText = string.format("States: 1:%s 2:%s 3:%s 4:%s", buttonStates.button1 and "ON" or "OFF", buttonStates.button2 and "ON" or "OFF", buttonStates.button3 and "ON" or "OFF", buttonStates.button4 and "ON" or "OFF") Gui.text(ctx, {x = 70, y = 315, width = 360, height = 22}, statesText, { fontSize = 16, alignX = "center", color = {1.0, 0.8, 0.8, 1.0}, }) local deltaX = input.mouseDeltaX or 0 local deltaY = input.mouseDeltaY or 0 Gui.text(ctx, {x = 70, y = 340, width = 360, height = 20}, string.format("Mouse d: %.1f, %.1f", deltaX, deltaY), { fontSize = 14, alignX = "center", color = {0.85, 0.9, 0.85, 1.0}, }) local grabState = window_get_mouse_grabbed and window_get_mouse_grabbed() or false local fpsLabel = fpsMode and "ON" or "OFF" local fpsToggleLabel = tostring(fpsToggleKey or "F1") Gui.text(ctx, {x = 70, y = 362, width = 360, height = 20}, string.format("FPS Mode: %s (grab=%s, %s toggle)", fpsLabel, grabState and "on" or "off", fpsToggleLabel), { fontSize = 14, alignX = "center", color = {0.85, 0.85, 0.95, 1.0}, }) if Gui.button(ctx, "fps_toggle", {x = 155, y = 385, width = 140, height = 28}, fpsMode and "FPS: ON" or "FPS: OFF") then setFpsMode(not fpsMode) end -- Reset button if Gui.button(ctx, "reset", {x = 175, y = 418, width = 100, height = 28}, "Reset") then buttonStates.button1 = false buttonStates.button2 = false buttonStates.button3 = false buttonStates.button4 = false statusMessage = "All buttons reset" log_trace("Reset button clicked") end end gui_context = ctx gui_input = input function get_scene_objects() return {} -- No 3D objects end function get_shader_paths() local default_variant = shader_variants.default or {} local vertex_label = default_variant.vertex or "inline" local fragment_label = default_variant.fragment or "inline" log_trace("GUI demo shader variants: default vertex=%s fragment=%s", vertex_label, fragment_label) return shader_variants end function get_view_projection(aspect) if not viewProjectionLogged then log_trace("GUI demo view projection: identity (aspect=%.2f)", aspect) viewProjectionLogged = true end return math3d.identity() end function get_gui_commands() updateFpsModeToggle() ctx:beginFrame(input) drawTestButtons() if fpsMode then local width, height = 1024, 768 if window_get_size then local w, h = window_get_size() if type(w) == "number" and type(h) == "number" then width, height = w, h end end Gui.cursor(ctx, {mouseX = width * 0.5, mouseY = height * 0.5, mouseDown = input.mouseDown}, { size = 18, thickness = 2, color = {0.9, 0.95, 1.0, 1.0}, activeColor = {1.0, 0.4, 0.2, 1.0}, }) else Gui.cursor(ctx, input, { size = 16, thickness = 2, color = {1.0, 0.9, 0.2, 1.0}, activeColor = {1.0, 0.35, 0.15, 1.0}, }) end ctx:endFrame() return ctx:getCommands() end