From 2b55ca9abf3155fbdb6549771c0e5ff6c4a7031a Mon Sep 17 00:00:00 2001 From: Signal Date: Mon, 26 Jan 2026 15:28:26 -0500 Subject: [PATCH] Fix models and buttons, and let containers handle inventories properly. --- README.md | 6 ++--- init.lua | 79 ++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 58 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 8afdf10..98e940e 100644 --- a/README.md +++ b/README.md @@ -278,9 +278,9 @@ Creates a model element. Methods: * `:style([state, ]props)`: Applies the styling properties `props` to the model when in the `state` state. If omitted, `state` is `"default"`. -* `:rotation(rotation[, continuous])`: Set the rotation of the model in the view, and optionally whether it is continuous. +* `:rotation(rotation_x[, rotation_y[, continuous]])`: Set the X and Y rotation of the model in the view, and optionally whether it is continuous. * `:mouse_control(state)`: Passing `false` will prevent the user from changing the model's rotation by clicking and dragging. -* `:animated(frames, speed)`: Sets an animation on the model defined by the given frame range and speed. +* `:animated(start, end_, speed)`: Sets an animation on the model defined by the given frame range and speed. ### `imfs.button(x, y, width, height, label)` @@ -295,7 +295,7 @@ Methods: ### `imfs.list(x, y, width, height, location = "current_player", list = "main"[, start])` -Creates an inventory element. +Creates an inventory element. Note that `width` and `height` are in units of inventory slots; when set to flex ratios, however, they will resolve to the maximum number of slots that can be displayed in their assigned width. `imfs.inventory` is an alias for this element. diff --git a/init.lua b/init.lua index 8cad266..4011a3c 100644 --- a/init.lua +++ b/init.lua @@ -163,9 +163,18 @@ local function get(e, x) local item = e[x] local mt = getmetatable(item) if mt == state or mt == DerivedState then - return fe(item()) + return fe(tostring(item())) end - return fe(item) + return fe(tostring(item)) +end + +local function get_raw(e, x) + local item = e[x] + local mt = getmetatable(item) + if mt == state or mt == DerivedState then + return item() + end + return item end -- MARK: Elements @@ -226,8 +235,8 @@ local function fs_named_tooltip(name, text, bgcolor, txtcolor) end local fs_label = { - render = function(e) - return string.format("label[%f,%f;%s]", get(e, "x"), get(e, "y"), get(e, "txt")) + render = function(e, x, y) + return string.format("label[%f,%f;%s]", x or get(e, "x"), y or get(e, "y"), get(e, "txt")) end } fs_label.__index = fs_label @@ -241,11 +250,16 @@ setmetatable(fs_label, { }) local fs_arealabel = { - render = function(e) + render = function(e, x, y, w, h) + x = x or get(e, "x") + y = y or get(e, "y") + w = w or get(e, "w") + h = h or get(e, "h") + if e._scrollable then - return string.format("textarea[%f,%f;%f,%f;;;%s]", get(e, "x"), get(e, "y"), get(e, "w"), get(e, "h"), get(e, "txt")) + return string.format("textarea[%f,%f;%f,%f;;;%s]", x, y, w, h, get(e, "txt")) else - return string.format("label[%f,%f;%f,%f;%s]", get(e, "x"), get(e, "y"), get(e, "w"), get(e, "h"), get(e, "txt")) + return string.format("label[%f,%f;%f,%f;%s]", x, y, w, h, get(e, "txt")) end end, scrollable = function(e) @@ -265,8 +279,8 @@ setmetatable(fs_arealabel, { }) local fs_hypertext = { - render = function(e) - return string.format("hypertext[%f,%f;%f,%f;%s]", get(e, "x"), get(e, "y"), get(e, "w"), get(e, "h"), hte(get(e, "txt"))) + render = function(e, x, y, w, h) + return string.format("hypertext[%f,%f;%f,%f;%s]", x or get(e, "x"), y or get(e, "y"), w or get(e, "w"), h or get(e, "h"), hte(get(e, "txt"))) end, onaction = function(e, fn) ctx._events.on_click[e.__id] = fn @@ -361,28 +375,46 @@ local fs_model = { for _, x in pairs(e._styles) do out[#out +1] = x:render() end + + local textures = get_raw(e, "textures") + if type(textures) ~= "string" then + textures = table.concat(textures, ",") + end + + local as = get(e, "_animation_start") + local ae = get(e, "_animation_end") + local animation = "" + if as and ae then + animation = string.format("%s,%s", fe(as), fe(ae)) + end + out[#out +1] = string.format( - "model[%f,%f;%f,%f;%s;%s;%s;%f;%s;%s;%s;%f]", + "model[%f,%f;%f,%f;%s;%s;%s;%s,%s;%s;%s;%s;%s]", x or get(e, "x"), y or get(e, "y"), w or get(e, "w"), h or get(e, "h"), e.__id, - get(e, "mesh"), get(e, "textures"), - get(e, "_rotation") or "", get(e, "_continuous") or "", - get(e, "_mouse_control"), - get(e, "_animation") or "", get(e, "_animation_speed") + get(e, "mesh"), textures, + get(e, "_rotation_x") or "", get(e, "_rotation_y") or "", get(e, "_continuous") or "", + get(e, "_mouse_control") or "", + animation, get(e, "_animation_speed") or "1" ) return table.concat(out) end, - rotation = function(e, rot, continuous) - e._rotation = rot + rotation = function(e, x, y, continuous) + e._rotation_x = x + e._rotation_y = y or 0 e._continuous = continuous + return e end, mouse_control = function(e, mouse_control) e._mouse_control = mouse_control ~= false and true or false + return e end, - animated = function(frames, speed) - e._animation = frames + animated = function(e, start, end_, speed) + e._animation_start = start + e._animation_end = end_ e._animation_speed = speed or 1 + return e end, style = add_elem_style, tooltip = add_elem_tooltip, @@ -390,7 +422,7 @@ local fs_model = { fs_model.__index = fs_model setmetatable(fs_model, { __call = function(_, x, y, w, h, mesh, textures) - local e = {x = x, y = y, w = w, h = h, mesh = mesh, textures = textures, mouse_control = true} + local e = {x = x, y = y, w = w, h = h, mesh = mesh, textures = textures, _mouse_control = true, _styles = {}} e.__id = new_id() setmetatable(e, fs_model) table.insert(ctx, e) @@ -421,12 +453,15 @@ local fs_button = { image = function(e, img, pressed_img) e._image = img e._image_pressed = pressed_img + return e end, item_image = function(e, item) e._item = item + return e end, exit = function(e) e._exit = true + return e end, onclick = function(e, fn) ctx._events.on_click[e.__id] = fn @@ -472,17 +507,13 @@ local fs_list = { w = w or get(e, "w") h = h or get(e, "h") - -- These lines will cause `w` and `h` to be interpreted as formspec coordinates rather than numbers of slots. - -- w = w -((w -1) /4) - -- h = h -((h -1) /4) - return string.format("list[%s;%s;%f,%f;%d,%d;%s]", get(e, "location"), get(e, "list"), x or get(e, "x"), y or get(e, "y"), w, h, get(e, "start")) end } fs_list.__index = fs_list setmetatable(fs_list, { __call = function(_, x, y, w, h, location, list, start) - local e = {x = x, y = y, w = w, h = h, location = location or "current_player", list = list or "main", start = start or ""} + local e = {x = x, y = y, w = type(w == "string") and w or w +((w -1) /4), h = type(h) == "string" and h or h +((h -1) /4), location = location or "current_player", list = list or "main", start = start or ""} e.__id = new_id() setmetatable(e, fs_list) table.insert(ctx, e)