diff options
| author | Alex Pickering <alex@cogarr.net> | 2026-02-01 13:14:32 -0600 |
|---|---|---|
| committer | Alexander M Pickering <alex@cogarr.net> | 2026-02-01 13:14:32 -0600 |
| commit | 3a975db66a3711f34e8b64bb27a8eaca79fdeca9 (patch) | |
| tree | fcc12f8f9d638ff575c1963796de76b7628854b4 /src/ui.moon | |
| download | ggj26-3a975db66a3711f34e8b64bb27a8eaca79fdeca9.tar.gz ggj26-3a975db66a3711f34e8b64bb27a8eaca79fdeca9.tar.bz2 ggj26-3a975db66a3711f34e8b64bb27a8eaca79fdeca9.zip | |
Diffstat (limited to 'src/ui.moon')
| -rw-r--r-- | src/ui.moon | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/src/ui.moon b/src/ui.moon new file mode 100644 index 0000000..25847bd --- /dev/null +++ b/src/ui.moon @@ -0,0 +1,269 @@ +hc = require("party.hc.init") +win = require("window") +log = require("log") +util = require("util") +Button = require("ui.button") +Joystick = require("ui.joystick") +Textbox = require("ui.textbox") +sprites = require("sprites") +color = require("color") + +ui_world = hc.new(64) + +am.eval_js(require("controller_bridge")) + +ui = {} +ui.events = { + touch: {} + mouse: {} + controller: {} + keyboard: {} +} +ui.button = (x,y,width,height,text,controller_binds,font) -> + font = font or sprites.yataghan64 + log.info(string.format("Creating button at (%d, %d) with size (%d, %d) and text %q",x,y,width,height,text),{"ui"}) + controller_binds = controller_binds or {} + assert(x and type(x) == "number", "x must be anumber") + assert(y and type(y) == "number", "y must be anumber") + assert(width and type(width) == "number", "width must be anumber") + assert(height and type(height) == "number", "height must be anumber") + button = Button(x,y,width,height,text, font) + ui.node\append(button.node) + bounds = ui_world\rectangle(x,y,width,height) + ui.events.touch[bounds] = button + ui.events.mouse[bounds] = button + for bind in *controller_binds + ui.events.controller[bind] = button + button + +ui.click = (x,y) -> + ui_world\shapesAt(x,y) + +ui.joystick = (x,y,r,controller_binds) -> + controller_binds = controller_binds or {} + joystick = Joystick(x,y,r) + ui.node\append(joystick.node) + bounds = ui_world\circle(x,y,r) + ui.events.touch[bounds] = joystick + for bind in *controller_binds + ui.events.controller[bind] = joystick + joystick + +ui.text = (x,y,width,height,text) -> + line_height = 16 + text = text or "" + rope = { + raw: text + width: 0 + height: 0 + lines: {} --list of line, a line is: + -- { + -- raw: string + -- tokens: token[] + -- width: number (pixels) + -- height: number (pixels) + -- } + -- A token is: + -- { + -- raw: string + -- width: number (pixels) + -- height: number (pixels) + -- } + } + current_line = { + raw: "" + tokens: {} + width: 0 + height: 0 + } + for word in text\gmatch("(%S+)") + t = am.text(sprites.yataghan32, " " .. word) + tps = t.width + if tps + current_line.width > width -- create a new line + rope.width = math.max(rope.width, current_line.width) + rope.height += line_height + current_line.height + if #rope.lines == 0 -- no line height for the first line + rope.height -= line_height + table.insert(rope.lines, current_line) + t = am.text(sprites.yataghan32, word) + token = { + raw: word + width: t.width + height: t.height + } + current_line = { + raw: word + tokens: { + token + } + width: t.width + height: t.height + } + else -- append token to this line + t = am.text(sprites.yataghan32, word) + token = { + raw: word + width: t.width + height: t.height + } + current_line.raw = current_line.raw .. " " .. word + current_line.width += tps + current_line.height = math.max(current_line.height, t.height) + table.insert(current_line.tokens, token) + if #current_line.tokens > 0 + table.insert(rope.lines, current_line) + group = am.group! + y_cursor = -line_height -- no line height for first line + for i = 1, #rope.lines + y_cursor -= line_height + line_pos = am.translate(x, y + y_cursor) + line_text = am.text(sprites.yataghan32, rope.lines[i].raw,color.am_color.foreground) + line_pos\append(line_text) + group\append(line_pos) + y_cursor -= rope.lines[i].height + rope.height = -y_cursor + if rope.height == 0 + rope.height = 1 + if rope.width == 0 + rope.width = 1 + bounds = ui_world\rectangle(x,y,rope.width, rope.height) + ui.node\append(group) + element = { + node: group + rope: rope + } + -- No events? + element + +ui.textbox = (x,y,width,height,value,placeholder) -> + value = value or "" + placeholder = placeholder or "" + textbox = Textbox(x,y,width,height,value,placeholder) + ui.node\append(textbox.node) + bounds = ui_world\rectangle(x,y,width,height) + ui.events.mouse[bounds] = textbox + ui.events.keyboard[textbox] = true + textbox + +ui.delete = (element) -> + ui.node\remove(element.node) + for b,e in pairs(ui.events.mouse) + if e == element + ui.events.mouse[b] = nil + if ui.events.keyboard[element] + ui.events.keyboard[element] = nil + for b,e in pairs(ui.events.touch) + if e == element + ui.events.touch[b] = nil + for b,e in pairs(ui.events.controller) + if e == element + ui.events.controller[b] = nil + +ui.node = am.group! + +has_fire = (obj) -> + assert(obj.fire, obj.__class.__name .. " doesn't have a .fire method") + +--ui.dbg = am.translate(0,0)\append(am.circle(vec2(0,0),5,vec4(0,0,0,1)))\append(am.text("Hello, world!")) +--ui.node\append(ui.dbg) + +ui.node\action(() -> + pos = win\mouse_position() + down = win\mouse_pressed("left") + up = win\mouse_released("left") + wheel = win\mouse_wheel_delta() + keys = win\keys_pressed() + am.eval_js("CONT.loop()") + cont_state = am.eval_js("CONT.last_state") + -- Debugging for mouse position: + --ui.dbg.position2d = pos + mo_tbl = + event: "mouse_over" + data: pos + md_tbl = + event: "mouse_down" + data: pos + mu_tbl = + event: "mouse_up" + data: pos + for collider,_ in pairs(ui_world\shapesAt(pos.x, pos.y)) + match = ui.events.mouse[collider] + if match + has_fire(match) + --log.info("Found button under mouse:" .. tostring(match), {"ui","mouseover"}) + match\fire(mo_tbl) + if down + log.info("Found button under mouse:" .. tostring(match), {"ui","mousedown"}) + match\fire(md_tbl) + if up + log.info("Found button under mouse:" .. tostring(match), {"ui","mouseup"}) + match\fire(mu_tbl) + if math.length(wheel) > 0 + etbl = + event: "mouse_scroll" + data: wheel + for collider, uiobj in pairs(ui.events.mouse) + has_fire(uiobj) + uiobj\fire(etbl) + if #keys > 0 + --print("Got keys:" .. tostring(keys)) + etbl = + event: "keys_pressed" + data: keys + shift: win\key_down("lshift") or win\key_down("rshift") + for uiobj, _ in pairs(ui.events.keyboard) + has_fire(uiobj) + if uiobj\fire(etbl) + break -- allow any keyboard listener to "trap" the signal by returning true + if cont_state.on + for axis,value in pairs(cont_state.axes) + name = "axis" .. axis + uiobj = ui.events.controller[name] + if uiobj and has_fire(uiobj) + etbl = + event: "controller_axis" + data: value + uiobj\fire(etbl) + for button,value in pairs(cont_state.buttons) + name = "button" .. button + uiobj = ui.events.controller[name] + if uiobj and has_fire(uiobj) + etbl = + event: "controller_pressed" + data: value + uiobj\fire(etbl) + +-- in_touch_events = { +-- "active_touch" +-- "touches_began" +-- } +-- for touch in *win\active_touches! +-- tpos = win\touch_position(touch) +-- etbl = +-- event: "active_touch" +-- data: tpos +-- for collider,_ in pairs(ui_world\shapesAt(tpos.x, tpos.y)) +-- print("Touched collider:", collider) +-- match = ui.events.touch[collider] +-- if match +-- has_fire(match) +-- match\fire(etbl) +-- delta = win\touch_delta(touch) +-- if math.length(delta) > 0 +-- dtbl = +-- event: "touch_delta" +-- data: delta +-- for _, uiobj in pairs(ui.events.touch) +-- has_fire(uiobj) +-- uiobj\fire(dtbl) +-- for touch in *win\touches_ended! +-- etbl = +-- event: "touches_ended" +-- data: win\touch_position(touch) +-- for _,uiobj in pairs(ui.events.touch) +-- has_fire(uiobj) +-- uiobj\fire(etbl) + -- todo: expand this with controller support. +) + +ui |
