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 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