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