diff --git a/font_api/fontform.lua b/font_api/fontform.lua new file mode 100644 index 0000000..e4952ed --- /dev/null +++ b/font_api/fontform.lua @@ -0,0 +1,167 @@ +--[[ + font_api mod for Minetest - Library to add font display capability + to display_api mod. + (c) Pierre-Yves Rollo + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +--]] + +local modname = minetest.get_current_modname() + +local contexts = {} + +minetest.register_on_leaveplayer(function(player) + if minetest.is_player(player) then + contexts[player:get_player_name()] = nil + end +end) + +local function get_context(playername) + if not contexts[playername] then + contexts[playername] = { playername = playername } + end + return contexts[playername] +end + +-- Show node formspec functions +local function show_node_formspec(playername, pos) + local meta = minetest.get_meta(pos) + + -- Decontextualize formspec + local fs = meta:get_string('formspec') + + if not fs then + return + end + + -- Change context and currrent_name references to nodemeta references + -- Change context and currrent_name references to nodemeta references + local nodemeta = string.format("nodemeta:%i,%i,%i", pos.x, pos.y ,pos.z) + fs = fs:gsub("current_name", nodemeta) + fs = fs:gsub("context", nodemeta) + + -- Change all ${} to their corresponding metadata values + local s, e + repeat + s, e = fs:find('%${.*}') + if s and e then + fs = fs:sub(1, s-1).. + minetest.formspec_escape(meta:get_string(fs:sub(s+2,e-1))).. + fs:sub(e+1) + end + until s == nil + + local context = get_context(playername) + context.node_pos = pos + + -- Find node on_receive_fields + local ndef = minetest.registered_nodes[minetest.get_node(pos).name] + if ndef and ndef.on_receive_fields then + context.on_receive_fields = ndef.on_receive_fields + end + + -- Show formspec + minetest.show_formspec(playername, modname..':context_formspec', fs) +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname ~= modname..':context_formspec' then + return + end + + if not minetest.is_player(player) then + return true + end + + local context = get_context(player:get_player_name()) + if context.on_receive_fields then + context.on_receive_fields(context.pos, '', fields, player) + end + return true +end) + +-- Specific functions + +local function show_font_formspec(playername) + local context = get_context(playername) + local fonts = {} + for name, _ in pairs(font_api.registered_fonts) do + fonts[#fonts+1] = name + end + table.sort(fonts) + + local fs = string.format( + "size[4,%s]%s%s%sbutton_exit[0,%s;4,1;cancel;Cancel]", + #fonts + 0.8, default.gui_bg, default.gui_bg_img, default.gui_slots, + #fonts) + + for line = 1, #fonts do + local font = font_api.get_font(fonts[line]) + local texture = font:make_text_texture(font.name, font:get_height()*5, + font:get_height()*1.2, 1, "center", "top", "#fff") + fs = string.format( + "%simage[0.1,%s;4.5,0.8;%s]button_exit[0,%s;4,1;font_%s;]", + fs, line-0.9, texture, line-1, font.name) + end + minetest.show_formspec(context.playername, modname..':font_list', fs) +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname ~= modname..':font_list' then + return + end + + if not minetest.is_player(player) then + return true + end + + local playername = player:get_player_name() + local context = get_context(playername) + + if not context.pos + or minetest.is_protected(context.pos, playername) then + return true + end + + if fields.quit == 'true' then + for name, _ in pairs(font_api.registered_fonts) do + if fields['font_'..name] then + local meta = minetest.get_meta(context.pos) + meta:set_string("font", name) + display_api.update_entities(context.pos) + end + end + + if context.callback and type(context.callback) == "function" then + -- Using after to avoid the "double close" bug + minetest.after(0, context.callback, playername, context.pos) + else + -- Using after to avoid the "double close" bug + minetest.after(0, show_node_formspec, playername, context.pos) + end + end + return true +end) + +-- @param player Player viewing the form +-- @param pos Node pos +-- @param callback function(playername, pos) to be called on form close +function font_api.show_font_list(player, pos, callback) + if minetest.is_player(player) then + local context = get_context(player:get_player_name()) + context.pos = pos + context.callback = callback + show_font_formspec(player:get_player_name()) + end +end diff --git a/font_api/init.lua b/font_api/init.lua index dc3a3e0..27cba99 100644 --- a/font_api/init.lua +++ b/font_api/init.lua @@ -29,9 +29,10 @@ font_api.path = minetest.get_modpath(font_api.name) dofile(font_api.path.."/font.lua") dofile(font_api.path.."/registry.lua") +dofile(font_api.path.."/fontform.lua") --- Standard on_display_update entity callback. --- Node should have a corresponding display_entity with size, resolution and +-- Node should have a corresponding display_entity with size, resolution and -- maxlines fields and optionally halign, valign and color fields -- @param pos Node position -- @param objref Object reference of entity @@ -49,8 +50,8 @@ function font_api.on_display_update(pos, objref) local maxlines = def.maxlines or 1 -- TODO:How to do w/o maxlines ? - objref:set_properties({ - textures={font:make_text_texture(text, + objref:set_properties({ + textures={font:make_text_texture(text, font:get_height(maxlines) * def.size.x / def.size.y / (def.aspect_ratio or 1), font:get_height(maxlines), @@ -62,4 +63,3 @@ end -- Compatibility font_lib = font_api - diff --git a/font_api/textures/font_api_center.png b/font_api/textures/font_api_center.png new file mode 100644 index 0000000..967db6a Binary files /dev/null and b/font_api/textures/font_api_center.png differ diff --git a/font_api/textures/font_api_font.png b/font_api/textures/font_api_font.png new file mode 100644 index 0000000..e450338 Binary files /dev/null and b/font_api/textures/font_api_font.png differ diff --git a/font_api/textures/font_api_left.png b/font_api/textures/font_api_left.png new file mode 100644 index 0000000..727410b Binary files /dev/null and b/font_api/textures/font_api_left.png differ diff --git a/font_api/textures/font_api_right.png b/font_api/textures/font_api_right.png new file mode 100644 index 0000000..16401d3 Binary files /dev/null and b/font_api/textures/font_api_right.png differ diff --git a/signs/nodes.lua b/signs/nodes.lua index c74ab6f..8e65e27 100644 --- a/signs/nodes.lua +++ b/signs/nodes.lua @@ -23,51 +23,58 @@ local F = function(...) return minetest.formspec_escape(S(...)) end -- Poster specific formspec local function display_poster(pos, node, player) - local formspec local meta = minetest.get_meta(pos) + local def = minetest.registered_nodes[node.name].display_entities["signs:display_text"] local font = font_api.get_font(meta:get_string("font") or def.font_name) + local fs + local fname = string.format("%s@%s:display", + node.name, minetest.pos_to_string(pos)) + -- Title texture local titletexture = font:make_text_texture( - meta:get_string("display_text"), font:get_height()*8.4, font:get_height(), 1, "center") + meta:get_string("display_text"), font:get_height()*8.4, + font:get_height(), 1, "center") - formspec = - "size[7,9]".. - "background[0,0;7,9;signs_poster_formspec.png]".. - "image[0,-0.2;8.4,2;"..titletexture.."]".. - "textarea[0.3,1.5;7,8;;"..minetest.colorize("#111", minetest.formspec_escape(meta:get_string("text")))..";]".. - "bgcolor[#0000]" + fs = string.format([=[ + size[7,9]bgcolor[#0000] + background[0,0;7,9;signs_poster_formspec.png] + image[0,-0.2;8.4,2;%s] + textarea[0.3,1.5;7,8;;%s;]]=], + titletexture, + minetest.colorize("#111", + minetest.formspec_escape(meta:get_string("text")))) if minetest.is_protected(pos, player:get_player_name()) then - formspec = formspec.. - "button_exit[2.5,8;2,1;ok;"..F("Close").."]" + fs = string.format("%sbutton_exit[2.5,8;2,1;ok;%s]", fs, F("Close")) else - formspec = formspec.. - "button[1,8;2,1;edit;"..F("Edit").."]".. - "button_exit[4,8;2,1;ok;"..F("Close").."]" + fs = string.format( + "%sbutton[1,8;2,1;edit;%s]button_exit[4,8;2,1;ok;%s]", + fs, F("Edit"), F("Close")) end - minetest.show_formspec(player:get_player_name(), - node.name.."@"..minetest.pos_to_string(pos)..":display", - formspec) + minetest.show_formspec(player:get_player_name(), fname, fs) end local function edit_poster(pos, node, player) - local formspec local meta = minetest.get_meta(pos) + local fs + local fname = string.format("%s@%s:edit", + node.name, minetest.pos_to_string(pos)) + if not minetest.is_protected(pos, player:get_player_name()) then - formspec = - "size[6.5,7.5]".. - default.gui_bg .. default.gui_bg_img .. default.gui_slots .. - "field[0.5,0.7;6,1;display_text;"..F("Title")..";".. - minetest.formspec_escape(meta:get_string("display_text")).."]".. - "textarea[0.5,1.7;6,6;text;"..F("Text")..";".. - minetest.formspec_escape(meta:get_string("text")).."]".. - "button_exit[2.25,7;2,1;write;"..F("Write").."]" - minetest.show_formspec(player:get_player_name(), - node.name.."@"..minetest.pos_to_string(pos)..":edit", - formspec) + fs = string.format([=[ + size[6.5,7.5]%s%s%s + field[0.5,0.7;6,1;display_text;%s;%s] + textarea[0.5,1.7;6,6;text;%s;%s] + button[1.25,7;2,1;font;%s] + button_exit[3.25,7;2,1;write;%s]]=], + default.gui_bg, default.gui_bg_img, default.gui_slots, F("Title"), + minetest.formspec_escape(meta:get_string("display_text")), + F("Text"), minetest.formspec_escape(meta:get_string("text")), + F("Title font"), F("Write")) + minetest.show_formspec(player:get_player_name(), fname, fs) end end @@ -80,15 +87,29 @@ local function on_receive_fields_poster(pos, formname, fields, player) if formname == node.name.."@"..minetest.pos_to_string(pos)..":display" and fields.edit then edit_poster(pos, node, player) + return true end if formname == node.name.."@"..minetest.pos_to_string(pos)..":edit" - and (fields.write or fields.key_enter) then - meta:set_string("display_text", fields.display_text) - meta:set_string("text", fields.text) - meta:set_string("infotext", "\""..fields.display_text - .."\"\n"..S("(right-click to read more text)")) - display_api.update_entities(pos) - display_poster(pos, node, player) + then + if (fields.write or fields.font or fields.key_enter) then + meta:set_string("display_text", fields.display_text) + meta:set_string("text", fields.text) + meta:set_string("infotext", "\""..fields.display_text + .."\"\n"..S("(right-click to read more text)")) + display_api.update_entities(pos) + end + if (fields.write or fields.key_enter) then + display_poster(pos, node, player) + elseif (fields.font) then + font_api.show_font_list(player, pos, function (playername, pos) + local player = minetest.get_player_by_name(playername) + local node = minetest.get_node(pos) + if player and node then + edit_poster(pos, node, player) + end + end) + end + return true end end end diff --git a/signs_api/init.lua b/signs_api/init.lua index ec3b0e9..9fcaa10 100644 --- a/signs_api/init.lua +++ b/signs_api/init.lua @@ -35,49 +35,53 @@ function signs_api.set_display_text(pos, text, font) else meta:set_string("infotext", "") end - meta:set_string("font", font) + if font then + meta:set_string("font", font) + end display_api.update_entities(pos) end function signs_api.set_formspec(pos) local meta = minetest.get_meta(pos) local ndef = minetest.registered_nodes[minetest.get_node(pos).name] - if ndef and ndef.display_entities + if ndef and ndef.display_entities and ndef.display_entities["signs:display_text"] then local maxlines = ndef.display_entities["signs:display_text"].maxlines - local formspec, formheight + local fs, y if maxlines == 1 then - formspec = - "field[0.5,0.7;5.5,1;display_text;"..F("Text").. - ";${display_text}]" - formheight = 2 + fs = "field[0.5,0.7;5.5,1;display_text;"..F("Text").. + ";${display_text}]" + y = 1.2 else local extralabel = "" if maxlines then extralabel = F(" (first %s lines only)"):format(maxlines) end - formspec = - "textarea[0.5,0.7;5.5,2;display_text;"..F("Text").."".. + fs = "textarea[0.5,0.7;5.5,2;display_text;"..F("Text").."".. extralabel..";${display_text}]" - formheight = 3 + y = 2.4 end - formspec = formspec.."button_exit[2,"..formheight..";2,1;ok;".. - F("Write").."]" - formheight = formheight + 1 - formspec = "size[6,"..formheight.."]"..default.gui_bg.. - default.gui_bg_img..default.gui_slots..formspec + fs = fs.."button[1,"..y..";2,1;font;"..F("Font").."]" + fs = fs.."button_exit[3,"..y..";2,1;ok;"..F("Write").."]" + y = y + 0.8 + fs = "size[6,"..y.."]"..default.gui_bg.. + default.gui_bg_img..default.gui_slots..fs - meta:set_string("formspec", formspec) + meta:set_string("formspec", fs) end end function signs_api.on_receive_fields(pos, formname, fields, player) if not minetest.is_protected(pos, player:get_player_name()) then if fields and (fields.ok or fields.key_enter) then - signs_api.set_display_text(pos, fields.display_text, fields.font) + signs_api.set_display_text(pos, fields.display_text) + end + if fields and (fields.font) then + signs_api.set_display_text(pos, fields.display_text) + font_api.show_font_list(player, pos) end end end @@ -183,7 +187,8 @@ function signs_api.register_sign(mod, name, model) on_destruct = display_api.on_destruct, on_rotate = signs_api.on_rotate, on_receive_fields = signs_api.on_receive_fields, - on_punch = function(pos, node, player, pointed_thing) + on_punch = function(pos, node, player, pointed_thing) + signs_api.set_formspec(pos) display_api.update_entities(pos) end, } @@ -211,7 +216,3 @@ end -- Text entity for all signs display_api.register_display_entity("signs:display_text") - - - - diff --git a/steles/nodes.lua b/steles/nodes.lua index 9b23b8d..79a9ed3 100644 --- a/steles/nodes.lua +++ b/steles/nodes.lua @@ -50,7 +50,7 @@ for i, material in ipairs(steles.materials) do display_entities = { ["steles:text"] = { on_display_update = font_api.on_display_update, - depth = -2/16 - display_api.entity_spacing, + depth = -2/16 - display_api.entity_spacing, top = -2/16, aspect_ratio = 0.4, size = { x = 10/16, y = 12/16 }, @@ -63,12 +63,14 @@ for i, material in ipairs(steles.materials) do end, on_construct = function(pos) local meta = minetest.get_meta(pos) - meta:set_string("formspec", "size[6,4]" - ..default.gui_bg .. default.gui_bg_img .. default.gui_slots - .."textarea[0.5,0.7;5.5,2;display_text;" - ..F("Displayed text (3 lines max)") - ..";${display_text}]" - .."button_exit[2,3;2,1;ok;"..F("Write").."]") + meta:set_string("formspec", string.format([=[ + size[6,4]%s%s%s + textarea[0.5,0.7;5.5,2;display_text;%s;${display_text}] + button[1,3;2,1;font;%s] + button_exit[3,3;2,1;ok;%s]]=], + default.gui_bg, default.gui_bg_img, default.gui_slots, + F("Displayed text (3 lines max)"), + F("Font"), F("Write"))) display_api.on_construct(pos) end, on_destruct = display_api.on_destruct, @@ -76,15 +78,17 @@ for i, material in ipairs(steles.materials) do on_receive_fields = function(pos, formname, fields, player) if not minetest.is_protected(pos, player:get_player_name()) then local meta = minetest.get_meta(pos) - if fields and fields.ok then + if fields.ok or fields.font then meta:set_string("display_text", fields.display_text) meta:set_string("infotext", "\""..fields.display_text.."\"") display_api.update_entities(pos) end + if fields.font then + font_api.show_font_list(player, pos) + end end end, on_punch = display_api.update_entities, }) end end -