496 lines
10 KiB
Lua
496 lines
10 KiB
Lua
local S = classroom.S
|
|
local FS = classroom.FS
|
|
local infos = {
|
|
{
|
|
title = S"Shout?",
|
|
type = "priv",
|
|
privs = { shout = true },
|
|
},
|
|
{
|
|
title = S"Fly?",
|
|
type = "priv",
|
|
privs = { fly = true },
|
|
},
|
|
{
|
|
title = S"Fast?",
|
|
type = "priv",
|
|
privs = { fast = true },
|
|
},
|
|
}
|
|
|
|
local function get_group(context)
|
|
if context and context.groupname then
|
|
return classroom.get_group_students(context.groupname)
|
|
else
|
|
return classroom.get_students()
|
|
end
|
|
end
|
|
|
|
local function check_perm(player)
|
|
return minetest.check_player_privs(player:get_player_name(), { teacher = true })
|
|
end
|
|
|
|
local DASHBOARD_HEADER = "formspec_version[3]size[13,10.85]"
|
|
|
|
local function get_formspec(player, context)
|
|
if not check_perm(player) then
|
|
return "label[0,0;" .. FS"Access denied" .. "]"
|
|
end
|
|
|
|
if context.selected_student and not minetest.get_player_by_name(context.selected_student) then
|
|
context.selected_student = nil
|
|
end
|
|
|
|
local function button(def)
|
|
local x = assert(def.x)
|
|
local y = assert(def.y)
|
|
local w = assert(def.w)
|
|
local h = assert(def.h)
|
|
local name = assert(def.name)
|
|
local text = assert(def.text)
|
|
local state = def.state
|
|
local tooltip = def.tooltip
|
|
local bgcolor = "#222"
|
|
|
|
-- Map different state values
|
|
if state == true or state == nil then
|
|
state = "active"
|
|
elseif state == false then
|
|
state = "disabled"
|
|
elseif state == "selected" then
|
|
state = "disabled"
|
|
bgcolor = "#53ac56"
|
|
end
|
|
|
|
-- Generate FS code
|
|
local fs
|
|
if state == "active" then
|
|
fs = {
|
|
("button[%f,%f;%f,%f;%s;%s]"):format(x, y, w, h, name, text)
|
|
}
|
|
elseif state == "disabled" then
|
|
name = "disabled_" .. name
|
|
|
|
fs = {
|
|
"container[", tostring(x), ",", tostring(y), "]",
|
|
|
|
"box[0,0;", tostring(w), ",", tostring(h), ";", bgcolor, "]",
|
|
|
|
"style[", name, ";border=false]",
|
|
"button[0,0;", tostring(w), ",", tostring(h), ";", name, ";", text, "]",
|
|
|
|
"container_end[]",
|
|
}
|
|
else
|
|
error("Unknown state: " .. state)
|
|
end
|
|
|
|
if tooltip then
|
|
fs[#fs + 1] = ("tooltip[%s;%s]"):format(name, tooltip)
|
|
end
|
|
|
|
return table.concat(fs, "")
|
|
end
|
|
|
|
local fs = {
|
|
"container[0.375,1.1]",
|
|
"tablecolumns[color;text",
|
|
}
|
|
|
|
context.select_toggle = context.select_toggle or "all"
|
|
|
|
for i, col in pairs(infos) do
|
|
fs[#fs + 1] = ";color;text,align=center"
|
|
if i == 1 then
|
|
fs[#fs + 1] = ",padding=2"
|
|
end
|
|
end
|
|
fs[#fs + 1] = "]"
|
|
|
|
do
|
|
fs[#fs + 1] = "tabheader[0,0;5.375,0.8;group;"
|
|
fs[#fs + 1] = FS"All"
|
|
local selected_group_idx = 1
|
|
local i = 2
|
|
for name, group in pairs(classroom.get_all_groups()) do
|
|
fs[#fs + 1] = ","
|
|
fs[#fs + 1] = minetest.formspec_escape(name)
|
|
if context.groupname and name == context.groupname then
|
|
selected_group_idx = i
|
|
end
|
|
i = i + 1
|
|
end
|
|
fs[#fs + 1] = ";"
|
|
fs[#fs + 1] = tostring(selected_group_idx)
|
|
fs[#fs + 1] = ";false;true]"
|
|
end
|
|
fs[#fs + 1] = "table[0,0;5.375,9.375;students;,Name"
|
|
for _, col in pairs(infos) do
|
|
fs[#fs + 1] = ",," .. col.title
|
|
end
|
|
|
|
local students = get_group(context)
|
|
local selection_id = ""
|
|
context.students = table.copy(students)
|
|
for i, student in pairs(students) do
|
|
fs[#fs + 1] = ",,"
|
|
fs[#fs + 1] = minetest.formspec_escape(student)
|
|
|
|
if student == context.selected_student then
|
|
selection_id = tostring(i + 1)
|
|
end
|
|
|
|
for _, col in pairs(infos) do
|
|
local color, value
|
|
if col.type == "priv" then
|
|
local has_priv = minetest.check_player_privs(student, col.privs)
|
|
color = has_priv and "green" or "red"
|
|
value = has_priv and FS"Yes" or FS"No"
|
|
end
|
|
|
|
fs[#fs + 1] = ","
|
|
fs[#fs + 1] = color
|
|
fs[#fs + 1] = ","
|
|
fs[#fs + 1] = minetest.formspec_escape(value)
|
|
end
|
|
end
|
|
|
|
fs[#fs + 1] = ";"
|
|
fs[#fs + 1] = selection_id
|
|
fs[#fs + 1] = "]"
|
|
|
|
fs[#fs + 1] = "container_end[]"
|
|
|
|
fs[#fs + 1] = "container[6.125,0.375]"
|
|
|
|
fs[#fs + 1] = "button[0,0;1.4,0.8;new_group;"
|
|
fs[#fs + 1] = FS"New Group"
|
|
fs[#fs + 1] = "]"
|
|
|
|
do
|
|
local btn = {
|
|
x = 0, y = 0,
|
|
w = 2.1, h = 0.8,
|
|
name = "new_group",
|
|
text = FS"New Group",
|
|
}
|
|
|
|
fs[#fs + 1] = button(btn)
|
|
end
|
|
|
|
do
|
|
local btn = {
|
|
x = 2.2, y = 0,
|
|
w = 2.1, h = 0.8,
|
|
name = "edit_group",
|
|
text = FS"Edit Group",
|
|
state = context.groupname ~= nil,
|
|
tooltip = not context.groupname and FS"Please select a group first",
|
|
}
|
|
|
|
fs[#fs + 1] = button(btn)
|
|
end
|
|
|
|
fs[#fs + 1] = "container[0,1.6]"
|
|
fs[#fs + 1] = "label[0,-0.3;"
|
|
fs[#fs + 1] = FS"Run actions on:"
|
|
fs[#fs + 1] = "]"
|
|
|
|
do
|
|
local btn = {
|
|
x = 0, y = 0,
|
|
w = 2.1, h = 0.8,
|
|
name = "select_all",
|
|
text = FS"All",
|
|
state = context.select_toggle == "all" and "selected" or "active",
|
|
}
|
|
|
|
fs[#fs + 1] = button(btn)
|
|
end
|
|
|
|
do
|
|
local btn = {
|
|
x = 2.2, y = 0,
|
|
w = 2.1, h = 0.8,
|
|
name = "select_group",
|
|
text = FS"Group",
|
|
}
|
|
|
|
if not context.groupname then
|
|
btn.state = "disabled"
|
|
btn.tooltip = FS"Please select a group first"
|
|
elseif context.select_toggle == "group" then
|
|
btn.state = "selected"
|
|
else
|
|
btn.state = "active"
|
|
end
|
|
|
|
fs[#fs + 1] = button(btn)
|
|
end
|
|
|
|
do
|
|
local btn = {
|
|
x = 4.4, y = 0,
|
|
w = 2.1, h = 0.8,
|
|
name = "select_selected",
|
|
text = FS"Selected",
|
|
}
|
|
|
|
if not context.selected_student then
|
|
btn.state = "disabled"
|
|
btn.tooltip = FS"Please select a student first"
|
|
elseif context.select_toggle == "selected" then
|
|
btn.state = "selected"
|
|
else
|
|
btn.state = "active"
|
|
end
|
|
|
|
fs[#fs + 1] = button(btn)
|
|
end
|
|
|
|
fs[#fs + 1] = "label[0,1.4;"
|
|
fs[#fs + 1] = FS"Actions:"
|
|
fs[#fs + 1] = "]"
|
|
|
|
local y = 1.7
|
|
do
|
|
local spacing = 0.1
|
|
local btn = {
|
|
x = 0, y = y,
|
|
w = (6.5 - spacing*2) / 3, h = 0.8,
|
|
}
|
|
|
|
for _, action in pairs(classroom.get_actions()) do
|
|
btn.state = "active"
|
|
btn.name = "action_" .. action.name
|
|
btn.text = minetest.formspec_escape(action.title)
|
|
btn.tooltip = minetest.formspec_escape(action.description)
|
|
fs[#fs + 1] = button(btn)
|
|
|
|
btn.x = btn.x + btn.w + spacing
|
|
if btn.x > 6.5 - btn.w then
|
|
y = y + btn.h + spacing
|
|
btn.x = 0
|
|
btn.y = y
|
|
end
|
|
end
|
|
|
|
if btn.x > 0 then
|
|
y = y + btn.h + spacing
|
|
end
|
|
end
|
|
|
|
y = y + 0.4
|
|
|
|
context.selected_student = "student1"
|
|
if context.selected_student then
|
|
fs[#fs + 1] = "container[0,"
|
|
fs[#fs + 1] = tostring(y)
|
|
fs[#fs + 1] = "]"
|
|
|
|
fs[#fs + 1] = "label[0,0;"
|
|
fs[#fs + 1] = FS("Selected user: @1", context.selected_student)
|
|
fs[#fs + 1] = "]"
|
|
fs[#fs + 1] = "button[0,0.3;2.1,0.8;teleport;"
|
|
fs[#fs + 1] = FS"Teleport to"
|
|
fs[#fs + 1] = "]"
|
|
|
|
fs[#fs + 1] = "container_end[]"
|
|
end
|
|
|
|
fs[#fs + 1] = "container_end[]"
|
|
fs[#fs + 1] = "container_end[]"
|
|
|
|
-- (8-1)*5/4 + 0.375*2 + 1 = 10.5
|
|
-- (8.6-1)*5/4 + 0.375*2 + 1 = 11.25
|
|
return table.concat(fs, "")
|
|
end
|
|
|
|
local function handle_results(player, context, fields)
|
|
if not check_perm(player) then
|
|
return false
|
|
end
|
|
|
|
if fields.students then
|
|
local evt = minetest.explode_table_event(fields.students)
|
|
local i = (evt.row or 0) - 1
|
|
if evt.type == "CHG" and i >= 1 and i <= #context.students then
|
|
context.selected_student = context.students[i]
|
|
return true
|
|
end
|
|
end
|
|
|
|
if fields.group then
|
|
if fields.group == "1" then
|
|
context.groupname = nil
|
|
else
|
|
local i = 2
|
|
for name, _ in pairs(classroom.get_all_groups()) do
|
|
if i == tonumber(fields.group) then
|
|
context.groupname = name
|
|
break
|
|
end
|
|
i = i + 1
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
if fields.select_all then
|
|
context.select_toggle = "all"
|
|
return true
|
|
elseif fields.select_group then
|
|
context.select_toggle = "group"
|
|
return true
|
|
elseif fields.select_selected then
|
|
context.select_toggle = "selected"
|
|
return true
|
|
end
|
|
|
|
if fields.teleport and context.selected_student then
|
|
local student = minetest.get_player_by_name(context.selected_student)
|
|
if student then
|
|
player:set_pos(student:get_pos())
|
|
return false
|
|
else
|
|
context.selected_student = nil
|
|
return true
|
|
end
|
|
end
|
|
|
|
if fields.new_group then
|
|
classroom.show_new_group(player)
|
|
return false
|
|
end
|
|
|
|
if fields.edit_group and context.groupname then
|
|
classroom.show_edit_group(player, context.groupname)
|
|
return false
|
|
end
|
|
|
|
for _, action in pairs(classroom.get_actions()) do
|
|
if fields["action_" .. action.name] then
|
|
local selector
|
|
if context.select_toggle == "all" then
|
|
selector = "*"
|
|
elseif context.select_toggle == "group" then
|
|
selector = "group:" .. context.groupname
|
|
elseif context.select_toggle == "selected" then
|
|
selector = "user:" .. context.selected_student
|
|
else
|
|
error("Unknown selector")
|
|
end
|
|
|
|
classroom.run_action(action.name, player, selector)
|
|
return true
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--
|
|
-- Show formspec
|
|
--
|
|
local _contexts = {}
|
|
function classroom.show_dashboard_formspec(player)
|
|
if not check_perm(player) then
|
|
return nil
|
|
end
|
|
|
|
local name = player:get_player_name()
|
|
local context = _contexts[name] or {}
|
|
_contexts[name] = context
|
|
|
|
minetest.show_formspec(player:get_player_name(), "classroom:dashboard",
|
|
DASHBOARD_HEADER .. get_formspec(player, context))
|
|
end
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
if formname ~= "classroom:dashboard" or not check_perm(player) then
|
|
return false
|
|
end
|
|
|
|
local context = _contexts[player:get_player_name()]
|
|
if not context then
|
|
return false
|
|
end
|
|
|
|
local ret = handle_results(player, context, fields)
|
|
if ret then
|
|
classroom.show_dashboard_formspec(player)
|
|
end
|
|
return ret
|
|
end)
|
|
|
|
|
|
--
|
|
-- Sfinv
|
|
--
|
|
if minetest.get_modpath("sfinv") then
|
|
sfinv.register_page("classroom:edu", {
|
|
title = S"Classroom",
|
|
is_in_nav = function(self, player, context)
|
|
return check_perm(player)
|
|
end,
|
|
get = function(self, player, context)
|
|
return sfinv.make_formspec(player, context, get_formspec(player, context),
|
|
false, DASHBOARD_HEADER)
|
|
end,
|
|
on_player_receive_fields = function(self, player, context, fields)
|
|
local ret = handle_results(player, context, fields)
|
|
if ret then
|
|
sfinv.set_player_inventory_formspec(player)
|
|
end
|
|
return ret
|
|
end,
|
|
})
|
|
|
|
local function on_grant_revoke(grantee, granter, priv)
|
|
if priv ~= "teacher" then
|
|
return
|
|
end
|
|
|
|
local player = minetest.get_player_by_name(grantee)
|
|
if not player then
|
|
return
|
|
end
|
|
|
|
minetest.after(0, function()
|
|
sfinv.set_player_inventory_formspec(player)
|
|
end)
|
|
end
|
|
|
|
minetest.register_on_priv_grant(on_grant_revoke)
|
|
minetest.register_on_priv_revoke(on_grant_revoke)
|
|
end
|
|
|
|
|
|
--
|
|
-- Chatcommand
|
|
--
|
|
minetest.register_chatcommand("classroom", {
|
|
privs = { teacher = true },
|
|
func = function(name, params)
|
|
local player = minetest.get_player_by_name(name)
|
|
if not player then
|
|
return false, "You must be online to open the GUI"
|
|
end
|
|
|
|
classroom.show_dashboard_formspec(player)
|
|
return true
|
|
end,
|
|
})
|
|
|
|
|
|
--
|
|
-- Unified Inventory
|
|
--
|
|
if minetest.get_modpath("unified_inventory") ~= nil then
|
|
unified_inventory.register_button("classroom", {
|
|
type = "image",
|
|
image = "classroom_icon.png",
|
|
tooltip = S("Classroom"),
|
|
action = classroom.show_dashboard_formspec,
|
|
})
|
|
end
|