-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathforms.lua
More file actions
166 lines (142 loc) · 4.78 KB
/
forms.lua
File metadata and controls
166 lines (142 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
--
-- Minetest snippets mod: A formspec API
--
-- This should probably be put in formspeclib.
--
local open_formspecs = {}
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
open_formspecs[name] = nil
end)
local get_player_by_name = minetest.global_exists('cloaking') and
cloaking.get_player_by_name or minetest.get_player_by_name
-- Formspec objects
-- You can create one of these per player and handle input
local Form = {}
local forms = {}
setmetatable(forms, {__mode = 'k'})
local function get(form)
if not forms[form] then
error('snippets.Form method called on a non-Form!', 3)
end
return forms[form]
end
-- Get unique formnames
local used_ids = {}
setmetatable(used_ids, {__mode = 'v'})
local function get_next_formname(form)
-- Iterate over it because of inconsistencies when getting the length of a
-- list containing nil.
local id = 1
for _ in ipairs(used_ids) do id = id + 1 end
-- ID should be equal to #used_ids + 1.
used_ids[id] = form
return 'snippets:form_' .. id
end
-- Override minetest.show_formspec
local show_formspec = minetest.show_formspec
function minetest.show_formspec(pname, formname, formspec)
if pname and (formspec ~= '' or formname == '') then
open_formspecs[pname] = nil
end
return show_formspec(pname, formname, formspec)
end
-- Show formspecs
function Form:show()
local data = get(self)
if not get_player_by_name(data.victim) then return false end
open_formspecs[data.victim] = self
local formspec = data.prepend .. data.formspec .. data.append
if formspec == '' then formspec = ' ' end
show_formspec(data.victim, data.formname, formspec)
return true
end
Form.open = Form.show
-- Close formspecs
function Form:close()
local data = get(self)
if open_formspecs[data.victim] == self then
minetest.close_formspec(data.victim, data.formname)
open_formspecs[data.victim] = nil
end
end
Form.hide = Form.close
-- Check if the form is open
function Form:is_open()
return open_formspecs[get(self).victim] == self
end
-- Prepends etc
function Form:get_prepend() return get(self).prepend end
function Form:get_formspec() return get(self).formspec end
function Form:get_append() return get(self).append end
function Form:set_prepend(text)
local data = get(self)
data.prepend = tostring(text or '')
if open_formspecs[data.victim] == self then self:show() end
end
function Form:set_formspec(text)
local data = get(self)
data.formspec = tostring(text or '')
if open_formspecs[data.victim] == self then self:show() end
end
function Form:set_append(text)
local data = get(self)
data.append = tostring(text or '')
if open_formspecs[data.victim] == self then self:show() end
end
-- Callbacks
function Form:add_callback(...)
local data, argc = get(self), select('#', ...)
local event, func
if argc == 1 then
event, func = '', ...
elseif argc == 2 then
event, func = ...
if type(event) ~= 'string' then
error('Invalid usage for snippets.Form:add_callback().', 2)
end
else
error('snippets.Form:add_callback() takes one or two arguments.', 2)
end
if not data.callbacks[event] then data.callbacks[event] = {} end
table.insert(data.callbacks[event], snippets.wrap_callback(func))
end
-- Create a Form object
function snippets.Form(name)
if minetest.is_player(name) then
name = name:get_player_name()
elseif type(name) ~= 'string' or not get_player_by_name(name) then
error('Attempted to create a Form for a non-existent player!', 2)
end
local form = {context = {}, pname = name}
setmetatable(form, {__index = Form})
forms[form] = {
victim = name, prepend = '', formspec = '', append = '',
callbacks = {}, formname = get_next_formname(form),
}
return form
end
function snippets.close_form(name)
if minetest.is_player(name) then name = name:get_player_name() end
if open_formspecs[name] then open_formspecs[name]:close() end
end
-- Callbacks
local function run_callbacks(callbacks, ...)
if not callbacks then return end
for _, func in ipairs(callbacks) do func(...) end
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname:sub(1, 14) ~= 'snippets:form_' then return end
local pname = player:get_player_name()
local form = open_formspecs[pname]
local data = forms[form]
if not data or data.formname ~= formname then return end
-- Nuke the formspec if required
if fields.quit then form:close() end
-- Run generic callbacks
run_callbacks(data.callbacks[''], form, fields)
-- Run field-specific callbacks
for k, v in pairs(fields) do
run_callbacks(data.callbacks[k], form, fields)
end
end)