From d1d9a296a8927e1767ef76e8408e0b84195fe77d Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Wed, 16 Jul 2025 14:51:19 -0500 Subject: [PATCH] separate clay layout and clay input --- prosperon/clay.cm | 18 ++++++------ prosperon/clay_input.cm | 63 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 10 deletions(-) create mode 100644 prosperon/clay_input.cm diff --git a/prosperon/clay.cm b/prosperon/clay.cm index 2501c755..2ea7cbc2 100644 --- a/prosperon/clay.cm +++ b/prosperon/clay.cm @@ -259,21 +259,19 @@ clay.textbox = function(str, on_change, ...configs) { var point = use('point') -// mousepos given in hud coordinates -clay.draw_commands = function draw_commands(cmds, pos = {x:0,y:0}, mousepos = {x:0,y:0}) +// Pure rendering function - no input handling +clay.draw_commands = function draw_commands(cmds, pos = {x:0,y:0}) { - cmds.hovered = null - for (var cmd of cmds) { var config = cmd.config var boundingbox = geometry.rect_move(cmd.boundingbox,point.add(pos,config.offset)) var content = geometry.rect_move(cmd.content,point.add(pos, config.offset)) - if (config.hovered && geometry.rect_point_inside(boundingbox, mousepos)) - { - config.hovered.__proto__ = config - config = config.hovered - cmds.hovered = cmd - } + + // Check if this box should use hover styling + if (cmd.state && cmd.state.hovered && config.hovered) { + config.hovered.__proto__ = config + config = config.hovered + } if (config.background_image) if (config.slice) diff --git a/prosperon/clay_input.cm b/prosperon/clay_input.cm new file mode 100644 index 00000000..aa1a934b --- /dev/null +++ b/prosperon/clay_input.cm @@ -0,0 +1,63 @@ +// clay_input.cm - Input handling for clay UI +// Separates input concerns from layout/rendering + +var geometry = use('geometry') +var point = use('point') + +var clay_input = {} + +// Hit-test boxes against a mouse position +// boxes: array of box objects from clay.draw() +// mousepos: {x, y} position to test +// prev_state: previous input state for tracking changes +clay_input.hit = function hit(boxes, mousepos, prev_state = {}) { + var hovered = null + var clicked = null + + // Find the topmost hovered box (iterate in reverse for proper z-order) + for (var i = boxes.length - 1; i >= 0; i--) { + var box = boxes[i] + var boundingbox = geometry.rect_move(box.boundingbox, box.config.offset) + if (geometry.rect_point_inside(boundingbox, mousepos)) { + hovered = box + break + } + } + + // Update hover state + if (hovered && hovered.config.hovered) { + hovered.state = hovered.state || {} + hovered.state.hovered = true + } + + // Clear previous hover state if different + if (prev_state.hovered && prev_state.hovered != hovered) { + prev_state.hovered.state = prev_state.hovered.state || {} + prev_state.hovered.state.hovered = false + } + + return { + hovered: hovered, + clicked: clicked + } +} + +// Handle click events +clay_input.click = function click(boxes, mousepos, button = 'left') { + var hit_result = clay_input.hit(boxes, mousepos) + var clicked = hit_result.hovered + + if (clicked && clicked.config.action) { + clicked.config.action() + return clicked + } + + return null +} + +// Get boxes with actions for navigation +clay_input.get_actionable = function get_actionable(boxes) { + return boxes.filter(box => box.config.action) +} + +return clay_input \ No newline at end of file