Skip to content

Commit

Permalink
Create Lua frontend GUI code
Browse files Browse the repository at this point in the history
  • Loading branch information
v-rob committed Jan 15, 2024
1 parent da6d942 commit e3a4f26
Show file tree
Hide file tree
Showing 10 changed files with 1,633 additions and 1 deletion.
9 changes: 8 additions & 1 deletion .luacheckrc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ read_globals = {
"Settings",

string = {fields = {"split", "trim"}},
table = {fields = {"copy", "getn", "indexof", "insert_all"}},
table = {fields = {
"copy",
"shallow_copy",
"getn",
"indexof",
"insert_all",
"merge"
}},
math = {fields = {"hypot", "round"}},
}

Expand Down
43 changes: 43 additions & 0 deletions builtin/common/misc_helpers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,15 @@ function table.copy(t, seen)
end


function table.shallow_copy(t)
local new = {}
for k, v in pairs(t) do
new[k] = v
end
return new
end


function table.insert_all(t, other)
for i=1, #other do
t[#t + 1] = other[i]
Expand All @@ -497,6 +506,15 @@ function table.insert_all(t, other)
end


function table.merge(...)
local new = {}
for _, t in ipairs{...} do
table.insert_all(new, t)
end
return new
end


function table.key_value_swap(t)
local ti = {}
for k,v in pairs(t) do
Expand Down Expand Up @@ -760,3 +778,28 @@ function core.parse_coordinates(x, y, z, relative_to)
local rz = core.parse_relative_number(z, relative_to.z)
return rx and ry and rz and { x = rx, y = ry, z = rz }
end

local function call(class, ...)
local obj = core.class(class)
if obj.new then
obj:new(...)
end
return obj
end

function core.class(super)
super = super or {}
super.__index = super
super.__call = call

return setmetatable({}, super)
end

function core.is_instance(obj, class)
if type(obj) ~= "table" then
return false
end

local meta = getmetatable(obj)
return meta == class or core.is_instance(meta, class)
end
2 changes: 2 additions & 0 deletions builtin/game/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
local scriptpath = core.get_builtin_path()
local commonpath = scriptpath .. "common" .. DIR_DELIM
local gamepath = scriptpath .. "game".. DIR_DELIM
local uipath = scriptpath .. "ui" .. DIR_DELIM

-- Shared between builtin files, but
-- not exposed to outer context
Expand Down Expand Up @@ -37,6 +38,7 @@ dofile(gamepath .. "forceloading.lua")
dofile(gamepath .. "statbars.lua")
dofile(gamepath .. "knockback.lua")
dofile(gamepath .. "async.lua")
dofile(uipath .. "init.lua")

core.after(0, builtin_shared.cache_content_ids)

Expand Down
100 changes: 100 additions & 0 deletions builtin/ui/elem.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
--[[
Minetest
Copyright (C) 2023 v-rob, Vincent Robinson <[email protected]>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
--]]

ui._elem_types = {}

function ui._new_type(base, type, type_id)
local class = core.class(base)

class._type = type
class._type_id = type_id

ui._elem_types[type] = class

return class
end

ui.Elem = ui._new_type(nil, "elem", 0)

function ui.Elem:new(props)
self._id = props.id or ui.new_id()
self._groups = {}
self._boxes = {main = true}
self._style = props.style or ui.Style{}
self._children = table.merge(props.children or props)

assert(ui.is_id(self._id), "Element ID must be an ID string")

for _, group in ipairs(props.groups or {}) do
assert(ui.is_id(group), "Element group must be an ID string")
self._groups[group] = true
end
end

function ui.Elem:_get_flat()
local elems = {self}
for _, child in ipairs(self._children) do
table.insert_all(elems, child:_get_flat())
end
return elems
end

function ui.Elem:_encode()
return ui._encode("Bz S", self._type_id, self._id, self:_encode_fields())
end

function ui.Elem:_encode_fields()
local fl = ui._make_flags()

if ui._shift_flag(fl, #self._children > 0) then
local child_ids = {}
for i, child in ipairs(self._children) do
child_ids[i] = child._id
end

ui._encode_flag(fl, "Z", ui._encode_array("z", child_ids))
end

self:_encode_box(fl, "main")

return ui._encode("S", ui._encode_flags(fl))
end

function ui.Elem:_encode_box(fl, name)
local box = self._boxes[name]

-- Element encoding always happens after styles are computed and boxes are
-- populated with style indices. So, if this box has any styles applied to
-- it, encode the relevant states.
if not ui._shift_flag(fl, box.n > 0) then
return
end

local box_fl = ui._make_flags()

-- For each state, check if there is any styling. If there is, add it
-- to the box's flags.
for i = ui._STATE_NONE, ui._NUM_STATES - 1 do
if ui._shift_flag(box_fl, box[i] ~= ui._NO_STYLE) then
ui._encode_flag(box_fl, "I", box[i])
end
end

ui._encode_flag(fl, "S", ui._encode_flags(box_fl))
end
28 changes: 28 additions & 0 deletions builtin/ui/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--[[
Minetest
Copyright (C) 2023 v-rob, Vincent Robinson <[email protected]>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
--]]

ui = {}

local UI_PATH = core.get_builtin_path() .. "ui" .. DIR_DELIM

dofile(UI_PATH .. "util.lua")
dofile(UI_PATH .. "selector.lua")
dofile(UI_PATH .. "style.lua")
dofile(UI_PATH .. "elem.lua")
dofile(UI_PATH .. "window.lua")
Loading

0 comments on commit e3a4f26

Please sign in to comment.