Initial commit
This commit is contained in:
commit
7e4a64c890
|
@ -0,0 +1,21 @@
|
|||
# MIT License
|
||||
|
||||
*Copyright © 2018 by luk3yx*
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,23 @@
|
|||
http://dev.minetest.net/formspec
|
||||
|
||||
size: Done!
|
||||
list: Incomplete
|
||||
image: image
|
||||
field: textbox
|
||||
pwdfield: textbox
|
||||
textarea: textbox
|
||||
label: text
|
||||
vertlabel: text
|
||||
button: button
|
||||
image_button: button
|
||||
item_image_button: button
|
||||
button_exit: button
|
||||
image_button_exit: button
|
||||
listcolors: formspeclib:raw_formspec
|
||||
bgcolor: formspeclib:raw_formspec
|
||||
background: formspeclib:raw_formspec
|
||||
textlist: combobox
|
||||
dropdown: combobox
|
||||
|
||||
Incomplete:
|
||||
list
|
|
@ -0,0 +1,117 @@
|
|||
--
|
||||
-- formspeclib core - Better and easier formspecs for Minetest
|
||||
--
|
||||
-- © 2017 by luk3yx
|
||||
--
|
||||
|
||||
-- This is only the core rendering process.
|
||||
|
||||
formspeclib = {}
|
||||
|
||||
local objects = {}
|
||||
|
||||
-- formspeclib.version: The version of formspeclib.
|
||||
formspeclib.version = 0.1
|
||||
|
||||
--
|
||||
-- formspeclib.render(): Renders a formspeclib object into a formspec.
|
||||
--
|
||||
-- Syntax: formspeclib.render(formspeclib_object, safe_mode, no_iterations)
|
||||
--
|
||||
-- formspeclib_object: The formspeclib object to render.
|
||||
-- safe_mode: Optional. If it is enabled, the renderer does safety
|
||||
-- checks so the server does not crash.
|
||||
-- no_iterations: Optional, not recommended. Only allows formspeclib
|
||||
-- objects that produce a direct formspec string.
|
||||
--
|
||||
formspeclib.render = function(formspec, safe_mode, no_iterations)
|
||||
if safe_mode and type(formspec) ~= 'table' then
|
||||
-- Don't throw an error, just don't render the formspec.
|
||||
return false
|
||||
end
|
||||
local compiled = ''
|
||||
local i
|
||||
local width
|
||||
local height
|
||||
if type(formspec.width) == 'number' then
|
||||
width = formspec.width
|
||||
else
|
||||
width = 0
|
||||
end
|
||||
if type(formspec.height) == 'number' then
|
||||
height = formspec.height
|
||||
else
|
||||
height = 0
|
||||
end
|
||||
for i = 1, #formspec do
|
||||
if safe_mode and type(formspec[i]) ~= 'table' then
|
||||
return false
|
||||
elseif not formspec[i].type then
|
||||
-- The formspec is defining the global width/height.
|
||||
if type(formspec[i].width) == 'number' then
|
||||
width = obj.width
|
||||
end
|
||||
if type(formspec[i].height) == 'number' then
|
||||
height = obj.height
|
||||
end
|
||||
elseif objects[formspec[i].type] then
|
||||
local a
|
||||
local o
|
||||
if safe_mode then
|
||||
a, o = pcall(objects[formspec[i].type], formspec[i], safe_mode)
|
||||
if not a then o = false end
|
||||
else
|
||||
o = objects[formspec[i].type](formspec[i], safe_mode)
|
||||
end
|
||||
if type(o) == 'string' then
|
||||
compiled = compiled .. o
|
||||
elseif type(o) == 'table' and not no_iterations then
|
||||
o = formspeclib.render(o, safe_mode, safe_mode or no_iterations)
|
||||
if not o then return false end
|
||||
compiled = compiled .. o
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
-- On unknown element
|
||||
return false
|
||||
end
|
||||
end
|
||||
if width > 0 and height > 0 then
|
||||
if default and default.gui_bg and default.gui_bg_img and default.gui_slots then
|
||||
compiled = default.gui_bg .. default.gui_bg_img .. default.gui_slots .. compiled
|
||||
end
|
||||
compiled = 'size[' ..
|
||||
tostring(width) .. ',' .. tostring(height) ..
|
||||
']' .. compiled
|
||||
end
|
||||
return compiled
|
||||
end
|
||||
|
||||
--
|
||||
-- formspeclib.register_object(): Create a formspeclib object
|
||||
--
|
||||
-- Syntax: formspeclib.register_object(name, function)
|
||||
--
|
||||
-- name: The name of the object (set in 'type'). It is recommended to make this
|
||||
-- 'mod:object' unless you are overriding an object.
|
||||
-- func: The function to generate the object. This function gets sent the
|
||||
-- formspec chunk to generate, and will return a string or formspeclib
|
||||
-- formspec, otherwise false to indicate an error.
|
||||
--
|
||||
formspeclib.register_object = function(name, func)
|
||||
if type(func) ~= 'function' then
|
||||
return false
|
||||
end
|
||||
objects[name] = func
|
||||
return true
|
||||
end
|
||||
|
||||
--
|
||||
-- formspeclib.escape(): Escape and stringify text.
|
||||
--
|
||||
-- This may seem useless, but it is actually quite useful.
|
||||
--
|
||||
formspeclib.escape = function(text)
|
||||
return minetest.formspec_escape(tostring(text))
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
default?
|
|
@ -0,0 +1,10 @@
|
|||
--
|
||||
-- formspeclib - Better and easier formspecs for Minetest
|
||||
-- Version 0.1
|
||||
--
|
||||
-- © 2017 by luk3yx
|
||||
--
|
||||
|
||||
local path = minetest.get_modpath('formspeclib')
|
||||
dofile(path .. '/core.lua') -- formspeclib core
|
||||
dofile(path .. '/objects.lua') -- Default formspeclib objects
|
|
@ -0,0 +1,240 @@
|
|||
--
|
||||
-- formspeclib default objects
|
||||
--
|
||||
-- These are unprefixed, however if you create a mod that registers objects,
|
||||
-- it is recommended to prefix them with your mod name to prevent conflicts.
|
||||
--
|
||||
|
||||
--
|
||||
-- Raw formspec data
|
||||
--
|
||||
-- Parameters: data
|
||||
--
|
||||
-- Example 'bgcolor[#fff;true;]':
|
||||
-- {
|
||||
-- type = 'formspeclib:raw_formspec',
|
||||
-- data = 'bgcolor[#fff;true;]',
|
||||
-- }
|
||||
--
|
||||
-- Using this is not recommended, and it is disabled in safe mode as it can be
|
||||
-- used to crash MT clients, effectively kicking an unsuspecting victim.
|
||||
--
|
||||
formspeclib.register_object('formspeclib:raw_formspec', function(obj, safe_mode)
|
||||
if safe_mode or type(obj.data) ~= 'string' then
|
||||
return false
|
||||
else
|
||||
return obj.data
|
||||
end
|
||||
end)
|
||||
|
||||
--
|
||||
-- A label
|
||||
--
|
||||
-- Parameters: x, y, align(?), text
|
||||
--
|
||||
-- Example 'label[1,1;Hello world!]':
|
||||
-- {
|
||||
-- type = 'text',
|
||||
-- x = 1,
|
||||
-- y = 1,
|
||||
-- align = 'left',
|
||||
-- text = 'Hello world!'
|
||||
-- }
|
||||
--
|
||||
-- align can be one of 'left', 'centre'/'center', or 'vertical'. If align is
|
||||
-- set to 'centre'/'center', you can also set width and height.
|
||||
--
|
||||
formspeclib.register_object('text', function(obj, safe_mode)
|
||||
if not obj.text or not obj.x or not obj.y then return false end
|
||||
if not obj.align then obj.align = 'left' end
|
||||
local x = formspeclib.escape(obj.x)
|
||||
local y = formspeclib.escape(obj.y)
|
||||
local text = formspeclib.escape(obj.text)
|
||||
if obj.align == 'left' then
|
||||
return 'label[' .. x .. ',' .. y .. ';' .. text .. ']'
|
||||
elseif obj.align == 'centre' or obj.align == 'center' then
|
||||
-- This magical hack lets you centre/center text in formspecs.
|
||||
-- Make sure your formspec ignores 'formspeclib:ignore'.
|
||||
local width = formspeclib.escape(obj.width or 8)
|
||||
local height = formspeclib.escape(obj.height or 0.5)
|
||||
return 'image_button[' .. x .. ',' .. y .. ';' .. width .. ',' ..
|
||||
height .. ';' .. formspeclib.escape('default_dirt.png^[colorize:#343434') .. ';formspeclib:ignore;' ..
|
||||
text .. ']'
|
||||
elseif obj.align == 'vertical' then
|
||||
return 'vertlabel[' .. x .. ',' .. y .. ';' .. text .. ']'
|
||||
else
|
||||
return false
|
||||
end
|
||||
end)
|
||||
|
||||
--
|
||||
-- An image
|
||||
--
|
||||
-- Parameters: x, y, width(?), height(?), image
|
||||
--
|
||||
-- Example 'image[1,1;1,1;default_dirt.png]':
|
||||
-- {
|
||||
-- type = 'image',
|
||||
-- x = 1,
|
||||
-- y = 1,
|
||||
-- width = 1,
|
||||
-- height = 1,
|
||||
-- image = 'default_dirt.png'
|
||||
-- }
|
||||
formspeclib.register_object('image', function(obj, safe_mode)
|
||||
if not obj.image or not obj.x or not obj.y then return false end
|
||||
local x = formspeclib.escape(obj.x)
|
||||
local y = formspeclib.escape(obj.y)
|
||||
local width = formspeclib.escape(obj.width or obj.height or 1)
|
||||
local height = formspeclib.escape(obj.height or obj.width or 1)
|
||||
local image = formspeclib.escape(obj.image)
|
||||
return 'image[' .. x .. ',' .. y .. ';' .. width .. ',' .. height .. ';' .. image .. ']'
|
||||
end)
|
||||
|
||||
--
|
||||
-- A button
|
||||
--
|
||||
-- Parameters: x, y, width, height(?), name, text, quit(?), image(?)
|
||||
--
|
||||
-- Example 'image_button_exit[1,1;3,1;button_cancel.png;cancel;Cancel]':
|
||||
-- {
|
||||
-- type = 'button',
|
||||
-- x = 1,
|
||||
-- y = 1,
|
||||
-- width = 3,
|
||||
-- height = 1,
|
||||
-- name = 'cancel',
|
||||
-- text = 'Cancel',
|
||||
-- quit = true,
|
||||
-- image = 'button_cancel.png',
|
||||
-- }
|
||||
--
|
||||
formspeclib.register_object('button', function(obj, safe_mode)
|
||||
if not obj.text or not obj.x or not obj.y or not obj.width or not obj.name then
|
||||
return false
|
||||
end
|
||||
local x = formspeclib.escape(obj.x)
|
||||
local y = formspeclib.escape(obj.y)
|
||||
local w = formspeclib.escape(obj.width)
|
||||
local h = formspeclib.escape(obj.height or 2)
|
||||
local name = formspeclib.escape(obj.name)
|
||||
local text = formspeclib.escape(obj.text)
|
||||
local t = 'button'
|
||||
local img = ''
|
||||
if obj.quit then
|
||||
t = t .. '_exit'
|
||||
end
|
||||
if obj.image then
|
||||
t = 'image_' .. t
|
||||
img = ';' .. formspeclib.escape(obj.image)
|
||||
if not obj.quit and not string.find(img, '.') then
|
||||
t = 'item_' .. t
|
||||
end
|
||||
end
|
||||
return t .. '[' .. x .. ',' .. y .. ';' .. w .. ',' .. h .. img .. ';' .. name .. ';' .. text .. ']'
|
||||
end)
|
||||
|
||||
--
|
||||
-- A text box
|
||||
--
|
||||
-- Parameters: x, y, width, height(?), name, label(?), default(?), password(?)
|
||||
--
|
||||
-- Example 'textarea[1,1;2,3;message;Yay]':
|
||||
-- {
|
||||
-- type = 'textbox',
|
||||
-- x = 1,
|
||||
-- y = 1,
|
||||
-- width = 2,
|
||||
-- height = 3,
|
||||
-- default = 'Yay',
|
||||
-- name = 'message',
|
||||
-- }
|
||||
formspeclib.register_object('textbox', function(obj, safe_mode)
|
||||
if obj.x or not obj.y or not obj.width or not obj.name then
|
||||
return false
|
||||
end
|
||||
local x = formspeclib.escape(obj.x)
|
||||
local y = formspeclib.escape(obj.y)
|
||||
local w = formspeclib.escape(obj.width)
|
||||
local name = formspeclib.escape(obj.name)
|
||||
local l = formspeclib.escape(obj.label or '')
|
||||
local def = formspeclib.escape(obj.default or '')
|
||||
local t = 'field'
|
||||
local img = ''
|
||||
def = ';' .. def
|
||||
local h
|
||||
if obj.height then
|
||||
h = formspeclib.escape(obj.height)
|
||||
t = 'textarea'
|
||||
else
|
||||
h = 2
|
||||
end
|
||||
if obj.password then
|
||||
if obj.default or obj.height then
|
||||
return false
|
||||
else
|
||||
t = 'pwd' .. t
|
||||
def = ''
|
||||
end
|
||||
end
|
||||
return t .. '[' .. x .. ',' .. y .. ';' .. w .. ',' .. h .. ';' .. name .. ';' .. l .. def .. ']'
|
||||
end)
|
||||
|
||||
--
|
||||
-- A combo box
|
||||
--
|
||||
-- Parameters: x, y, width, height(?), name, label(?), default(?), password(?)
|
||||
--
|
||||
formspeclib.register_object('combobox', function(obj, safe_mode)
|
||||
if not obj.x or not obj.y or not obj.width or not obj.name or not obj.items then
|
||||
return false
|
||||
end
|
||||
local x = formspeclib.escape(obj.x)
|
||||
local y = formspeclib.escape(obj.y)
|
||||
local w = formspeclib.escape(obj.width)
|
||||
local name = formspeclib.escape(obj.name)
|
||||
local l = formspeclib.escape(obj.label or '')
|
||||
local def = formspeclib.escape(obj.default or '')
|
||||
local img = ''
|
||||
def = ';' .. def
|
||||
local h
|
||||
local t
|
||||
local i
|
||||
local items
|
||||
for i = 1, #obj.items do
|
||||
if i ~= 1 then i = i .. ';' end
|
||||
items = items .. obj.items[i]
|
||||
end
|
||||
if obj.height then
|
||||
h = formspeclib.escape(obj.height)
|
||||
t = 'textlist'
|
||||
else
|
||||
h = 2
|
||||
t = 'dropdown'
|
||||
end
|
||||
return t .. '[' .. x .. ',' .. y .. ';' .. w .. ',' .. h .. ';' .. name .. ';' .. l .. def .. ']'
|
||||
end)
|
||||
|
||||
--
|
||||
-- An inventory list
|
||||
--
|
||||
-- Parameters: location(?), name(?), x, y, width, height, start_at(?)
|
||||
--
|
||||
formspeclib.register_object('inventory', function(obj, safe_mode)
|
||||
if not obj.x or not obj.y or not obj.width or not obj.height then
|
||||
return false
|
||||
end
|
||||
local x = formspeclib.escape(obj.x)
|
||||
local y = formspeclib.escape(obj.y)
|
||||
local w = formspeclib.escape(obj.width)
|
||||
local h = formspeclib.escape(obj.height)
|
||||
local location = formspeclib.escape(obj.location or 'current_player')
|
||||
local name = formspeclib.escape(obj.name or 'main')
|
||||
local start = formspeclib.escape(obj.start_at or '')
|
||||
if safe_mode and location ~= 'current_player' and location ~= 'context' then
|
||||
-- You are not allowed to use other locations in safe mode.
|
||||
return false
|
||||
end
|
||||
return 'list[' .. location .. ';' .. name .. ';' .. x .. ',' .. y .. ';' ..
|
||||
w .. ',' .. h .. ';' .. start .. ']'
|
||||
end)
|
Reference in New Issue