mirror of https://github.com/minetest/minetest.git
131 lines
3.5 KiB
Lua
131 lines
3.5 KiB
Lua
--[[
|
|
Minetest
|
|
Copyright (C) 2023 v-rob, Vincent Robinson <robinsonvincent89@gmail.com>
|
|
|
|
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, id_required)
|
|
local class = core.class(base)
|
|
|
|
class._type = type
|
|
class._type_id = type_id
|
|
class._id_required = id_required
|
|
|
|
ui._elem_types[type] = class
|
|
|
|
return class
|
|
end
|
|
|
|
function ui.derive_elem(base, type)
|
|
assert(not ui._elem_types[type], "Derived element name already used")
|
|
return ui._new_type(base, type, base._type_id, base._id_required)
|
|
end
|
|
|
|
ui.Elem = ui._new_type(nil, "elem", 0x00, false)
|
|
|
|
ui.Label = ui.derive_elem(ui.Elem, "label")
|
|
ui.Image = ui.derive_elem(ui.Elem, "image")
|
|
|
|
function ui.Elem:new(props)
|
|
if self._id_required then
|
|
assert(ui.is_id(props.id), "ID is required for '" .. self._type .. "'")
|
|
end
|
|
|
|
self._id = props.id or ui.new_id()
|
|
self._groups = {}
|
|
self._boxes = {main = true}
|
|
self._style = props.style or ui.Style{props = props}
|
|
|
|
self._children = table.merge(props.children or props)
|
|
|
|
-- Set by parent ui.Elem
|
|
self._parent = nil
|
|
self._index = nil
|
|
self._rindex = nil
|
|
|
|
-- Set by ui.Window
|
|
self._window = nil
|
|
|
|
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
|
|
|
|
for i, child in ipairs(self._children) do
|
|
assert(child._parent == nil, "Element already has a parent")
|
|
assert(not core.is_instance(child, ui.Root),
|
|
"ui.Root can only be a root element")
|
|
|
|
child._parent = self
|
|
child._index = i
|
|
child._rindex = #self._children - i + 1
|
|
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, self._boxes.main)
|
|
|
|
return ui._encode_flags(fl)
|
|
end
|
|
|
|
function ui.Elem:_encode_box(fl, box)
|
|
-- 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
|