Luanti rename, add ButtonURL support

This commit is contained in:
luk3yx 2024-11-08 15:52:39 +13:00
parent 136f2b1637
commit f306f01f57
8 changed files with 154 additions and 122 deletions

View File

@ -5,11 +5,11 @@ globals = {
} }
read_globals = { read_globals = {
'core',
'dump', 'dump',
'formspec_ast', 'formspec_ast',
'fs51', 'fs51',
'hud_fs', 'hud_fs',
'minetest',
string = {fields = {'split', 'trim'}}, string = {fields = {'split', 'trim'}},
table = {fields = {'copy', 'indexof'}} table = {fields = {'copy', 'indexof'}}
} }

View File

@ -1,8 +1,8 @@
# flow # flow
[![ContentDB](https://content.minetest.net/packages/luk3yx/flow/shields/downloads/)](https://content.minetest.net/packages/luk3yx/flow/) [![ContentDB](https://content.luanti.org/packages/luk3yx/flow/shields/downloads/)](https://content.luanti.org/packages/luk3yx/flow/)
An experimental layout manager and formspec API replacement for Minetest. An experimental layout manager and formspec API replacement for Luanti (formerly Minetest).
Vaguely inspired by Flutter and GTK. Vaguely inspired by Flutter and GTK.
[Online tutorial/demo](https://luk3yx.gitlab.io/minetest-flow-playground/) [Online tutorial/demo](https://luk3yx.gitlab.io/minetest-flow-playground/)
@ -28,14 +28,14 @@ Vaguely inspired by Flutter and GTK.
- No having to worry about state. - No having to worry about state.
- Values of fields, scrollbars, checkboxes, etc are remembered when - Values of fields, scrollbars, checkboxes, etc are remembered when
redrawing a form and are automatically applied. redrawing a form and are automatically applied.
- Has an [inspector mod](https://content.minetest.net/packages/luk3yx/flow_inspector/) - Has an [inspector mod](https://content.luanti.org/packages/luk3yx/flow_inspector/)
to help with developing and debugging forms. to help with developing and debugging forms.
- Some common security issues with formspec input handling are mitigated. - Some common security issues with formspec input handling are mitigated.
## Limitations ## Limitations
- This mod doesn't support all of the features that regular formspecs do. - This mod doesn't support all of the features that regular formspecs do.
- [FS51](https://content.minetest.net/packages/luk3yx/fs51/) is required if - [FS51](https://content.luanti.org/packages/luk3yx/fs51/) is required if
you want to have full support for Minetest 5.3 and below. you want to have full support for Minetest 5.3 and below.
- Make sure you're using the latest version of flow if you are on MT 5.10-dev - Make sure you're using the latest version of flow if you are on MT 5.10-dev
or later, older versions used a hack which no longer works. or later, older versions used a hack which no longer works.
@ -74,7 +74,7 @@ local my_gui = flow.make_gui(function(player, ctx)
on_event = function(player, ctx) on_event = function(player, ctx)
-- flow should guarantee that `ctx.form.my_dropdown` exists, even if the client doesn't send my_dropdown to the server. -- flow should guarantee that `ctx.form.my_dropdown` exists, even if the client doesn't send my_dropdown to the server.
local selected_idx = ctx.form.my_dropdown local selected_idx = ctx.form.my_dropdown
minetest.chat_send_player(player:get_player_name(), "You have selected item #" .. selected_idx .. "!") core.chat_send_player(player:get_player_name(), "You have selected item #" .. selected_idx .. "!")
end, end,
} }
} }
@ -118,7 +118,7 @@ end)
-- Re-shows the form for all players with the "server" privilege -- Re-shows the form for all players with the "server" privilege
my_gui:update_where(function(player, ctx) my_gui:update_where(function(player, ctx)
return minetest.check_player_privs(player, "server") return core.check_player_privs(player, "server")
end) end)
-- Re-shows the form for all players with the form open -- Re-shows the form for all players with the form open
@ -148,12 +148,12 @@ a newline without pasting it in).
These utilities likely aren't compatible with flow. These utilities likely aren't compatible with flow.
- [fs_layout](https://github.com/fluxionary/minetest-fs_layout/) is another mod library that does automatic formspec element positioning. - [fs_layout](https://github.com/fluxionary/minetest-fs_layout/) is another mod library that does automatic formspec element positioning.
- [fslib](https://content.minetest.net/packages/LMD/fslib/) is a small mod library that lets you build formspec strings. - [fslib](https://content.luanti.org/packages/LMD/fslib/) is a small mod library that lets you build formspec strings.
- [Just_Visiting's formspec editor](https://content.minetest.net/packages/Just_Visiting/formspec_editor) is a Minetest (sub)game that lets you edit formspecs and preview them as you go - [Just_Visiting's formspec editor](https://content.luanti.org/packages/Just_Visiting/formspec_editor) is a Minetest (sub)game that lets you edit formspecs and preview them as you go
- [kuto](https://github.com/TerraQuest-Studios/kuto/) is a formspec library that has some extra widgets/components and has a callback API. Some automatic sizing can be done for buttons. - [kuto](https://github.com/TerraQuest-Studios/kuto/) is a formspec library that has some extra widgets/components and has a callback API. Some automatic sizing can be done for buttons.
- It may be possible to use kuto's components with flow somehow as they both use formspec_ast internally. - It may be possible to use kuto's components with flow somehow as they both use formspec_ast internally.
- kuto was the the source of the "on_event" function idea. - kuto was the the source of the "on_event" function idea.
- [My web-based formspec editor](https://forum.minetest.net/viewtopic.php?f=14&t=24130) lets you add elements and drag+drop them, however it doesn't support all formspec features. - [My web-based formspec editor](https://forum.luanti.org/viewtopic.php?f=14&t=24130) lets you add elements and drag+drop them, however it doesn't support all formspec features.
## Elements ## Elements
@ -469,7 +469,7 @@ player. Elements hidden this way will still take up space like with
<summary><b>Using a form as an inventory</b></summary> <summary><b>Using a form as an inventory</b></summary>
> [!TIP] > [!TIP]
> Consider using [Sway](https://content.minetest.net/packages/lazerbeak12345/sway/) > Consider using [Sway](https://content.luanti.org/packages/lazerbeak12345/sway/)
> instead if you want to use flow as an inventory replacement while still > instead if you want to use flow as an inventory replacement while still
> having some way for other mods to extend the inventory. > having some way for other mods to extend the inventory.

View File

@ -4,7 +4,7 @@ This is probably broken.
### `gui.AnimatedImage` ### `gui.AnimatedImage`
Equivalent to Minetest's `animated_image[]` element. Equivalent to Luanti's `animated_image[]` element.
**Example** **Example**
```lua ```lua
@ -33,7 +33,7 @@ gui.AnimatedImage {
### `gui.Box` ### `gui.Box`
Equivalent to Minetest's `box[]` element. Equivalent to Luanti's `box[]` element.
**Example** **Example**
```lua ```lua
@ -46,7 +46,7 @@ gui.Box {
### `gui.Button` ### `gui.Button`
Equivalent to Minetest's `button[]` element. Equivalent to Luanti's `button[]` element.
**Example** **Example**
```lua ```lua
@ -60,7 +60,7 @@ gui.Button {
### `gui.ButtonExit` ### `gui.ButtonExit`
Equivalent to Minetest's `button_exit[]` element. Equivalent to Luanti's `button_exit[]` element.
**Example** **Example**
```lua ```lua
@ -72,9 +72,39 @@ gui.ButtonExit {
} }
``` ```
### `gui.ButtonURL`
Equivalent to Luanti's `button_url[]` element.
**Example**
```lua
gui.ButtonURL{
w = 1, -- Optional
h = 2, -- Optional
name = "my_button_url", -- Optional
label = "Hello world!",
url = "Hello world!",
}
```
### `gui.ButtonUrlExit`
Equivalent to Luanti's `button_url_exit[]` element.
**Example**
```lua
gui.ButtonUrlExit{
w = 1, -- Optional
h = 2, -- Optional
name = "my_button_url_exit", -- Optional
label = "Hello world!",
url = "Hello world!",
}
```
### `gui.Checkbox` ### `gui.Checkbox`
Equivalent to Minetest's `checkbox[]` element. Equivalent to Luanti's `checkbox[]` element.
**Example** **Example**
```lua ```lua
@ -87,7 +117,7 @@ gui.Checkbox {
### `gui.Dropdown` ### `gui.Dropdown`
Equivalent to Minetest's `dropdown[]` element. Equivalent to Luanti's `dropdown[]` element.
**Example** **Example**
```lua ```lua
@ -103,7 +133,7 @@ gui.Dropdown {
### `gui.Field` ### `gui.Field`
Equivalent to Minetest's `field[]` element. Equivalent to Luanti's `field[]` element.
**Example** **Example**
```lua ```lua
@ -122,7 +152,7 @@ gui.Field {
### `gui.Hypertext` ### `gui.Hypertext`
Equivalent to Minetest's `hypertext[]` element. Equivalent to Luanti's `hypertext[]` element.
**Example** **Example**
```lua ```lua
@ -136,7 +166,7 @@ gui.Hypertext {
### `gui.Image` ### `gui.Image`
Equivalent to Minetest's `image[]` element. Equivalent to Luanti's `image[]` element.
**Example** **Example**
```lua ```lua
@ -153,7 +183,7 @@ gui.Image {
### `gui.ImageButton` ### `gui.ImageButton`
Equivalent to Minetest's `image_button[]` element. Equivalent to Luanti's `image_button[]` element.
**Example** **Example**
```lua ```lua
@ -171,7 +201,7 @@ gui.ImageButton {
### `gui.ImageButtonExit` ### `gui.ImageButtonExit`
Equivalent to Minetest's `image_button_exit[]` element. Equivalent to Luanti's `image_button_exit[]` element.
**Example** **Example**
```lua ```lua
@ -189,7 +219,7 @@ gui.ImageButtonExit {
### `gui.ItemImage` ### `gui.ItemImage`
Equivalent to Minetest's `item_image[]` element. Equivalent to Luanti's `item_image[]` element.
**Example** **Example**
```lua ```lua
@ -202,7 +232,7 @@ gui.ItemImage {
### `gui.ItemImageButton` ### `gui.ItemImageButton`
Equivalent to Minetest's `item_image_button[]` element. Equivalent to Luanti's `item_image_button[]` element.
**Example** **Example**
```lua ```lua
@ -217,7 +247,7 @@ gui.ItemImageButton {
### `gui.Label` ### `gui.Label`
Equivalent to Minetest's `label[]` element. Equivalent to Luanti's `label[]` element.
**Example** **Example**
```lua ```lua
@ -228,7 +258,7 @@ gui.Label {
### `gui.List` ### `gui.List`
Equivalent to Minetest's `list[]` element. Equivalent to Luanti's `list[]` element.
**Example** **Example**
```lua ```lua
@ -246,7 +276,7 @@ gui.List {
### `gui.Model` ### `gui.Model`
Equivalent to Minetest's `model[]` element. Equivalent to Luanti's `model[]` element.
**Example** **Example**
```lua ```lua
@ -278,7 +308,7 @@ gui.Model {
### `gui.Pwdfield` ### `gui.Pwdfield`
Equivalent to Minetest's `pwdfield[]` element. Equivalent to Luanti's `pwdfield[]` element.
**Example** **Example**
```lua ```lua
@ -292,7 +322,7 @@ gui.Pwdfield {
### `gui.Table` ### `gui.Table`
Equivalent to Minetest's `table[]` element. Equivalent to Luanti's `table[]` element.
**Example** **Example**
```lua ```lua
@ -309,7 +339,7 @@ gui.Table {
### `gui.TableColumns` ### `gui.TableColumns`
Equivalent to Minetest's `tablecolumns[]` element. Equivalent to Luanti's `tablecolumns[]` element.
**Example** **Example**
```lua ```lua
@ -326,7 +356,7 @@ gui.TableColumns {
### `gui.TableOptions` ### `gui.TableOptions`
Equivalent to Minetest's `tableoptions[]` element. Equivalent to Luanti's `tableoptions[]` element.
**Example** **Example**
```lua ```lua
@ -337,7 +367,7 @@ gui.TableOptions {
### `gui.Textarea` ### `gui.Textarea`
Equivalent to Minetest's `textarea[]` element. Equivalent to Luanti's `textarea[]` element.
**Example** **Example**
```lua ```lua
@ -352,7 +382,7 @@ gui.Textarea {
### `gui.Textlist` ### `gui.Textlist`
Equivalent to Minetest's `textlist[]` element. Equivalent to Luanti's `textlist[]` element.
**Example** **Example**
```lua ```lua
@ -368,7 +398,7 @@ gui.Textlist {
### `gui.Tooltip` ### `gui.Tooltip`
Equivalent to Minetest's `tooltip[]` element. Equivalent to Luanti's `tooltip[]` element.
**Example** **Example**
```lua ```lua
@ -382,7 +412,7 @@ gui.Tooltip {
### `gui.Vertlabel` ### `gui.Vertlabel`
Equivalent to Minetest's `vertlabel[]` element. Equivalent to Luanti's `vertlabel[]` element.
**Example** **Example**
```lua ```lua

View File

@ -1,5 +1,5 @@
-- --
-- Minetest formspec layout engine -- Luanti formspec layout engine
-- --
-- Copyright © 2022 by luk3yx -- Copyright © 2022 by luk3yx
-- --

View File

@ -1,5 +1,5 @@
-- --
-- Minetest formspec layout engine -- Luanti formspec layout engine
-- --
-- Copyright © 2022 by luk3yx -- Copyright © 2022 by luk3yx
-- --
@ -19,7 +19,7 @@
-- You can run /flow-example in singleplayer to open this form -- You can run /flow-example in singleplayer to open this form
local gui = flow.widgets local gui = flow.widgets
local S = minetest.get_translator("flow") local S = core.get_translator("flow")
local elements = {"box", "label", "image", "field", "checkbox", "list"} local elements = {"box", "label", "image", "field", "checkbox", "list"}
local alignments = {"auto", "start", "end", "centre", "fill"} local alignments = {"auto", "start", "end", "centre", "fill"}
@ -99,7 +99,7 @@ local my_gui = flow.make_gui(function(player, ctx)
ctx.form.checkbox = not ctx.form.checkbox ctx.form.checkbox = not ctx.form.checkbox
-- Send a chat message -- Send a chat message
minetest.chat_send_player(player:get_player_name(), S"Toggled!") core.chat_send_player(player:get_player_name(), S"Toggled!")
-- Return true to tell flow to redraw the formspec -- Return true to tell flow to redraw the formspec
return true return true

View File

@ -7,7 +7,8 @@ hide_elements = {
'background', 'background9', 'scroll_container', 'scrollbar', 'tabheader' 'background', 'background9', 'scroll_container', 'scrollbar', 'tabheader'
} }
hide_comments = {'x', 'y', 'w', 'h', 'name', 'selected'} hide_comments = {'x', 'y', 'w', 'h', 'name', 'selected'}
special_case_names = {'tablecolumns': 'TableColumns', special_case_names = {'button_url': 'ButtonURL',
'tablecolumns': 'TableColumns',
'tableoptions': 'TableOptions'} 'tableoptions': 'TableOptions'}
@ -94,7 +95,7 @@ def element_to_docs(element_name, variants):
lines = [ lines = [
f'### `gui.{flow_name}`\n', f'### `gui.{flow_name}`\n',
f"Equivalent to Minetest's `{element_name}[]` element.\n", f"Equivalent to Luanti's `{element_name}[]` element.\n",
'**Example**', '**Example**',
'```lua', '```lua',
f'gui.{flow_name}{{' f'gui.{flow_name}{{'

View File

@ -1,5 +1,5 @@
-- --
-- Minetest formspec layout engine -- Luanti formspec layout engine
-- --
-- Copyright © 2022 by luk3yx -- Copyright © 2022 by luk3yx
-- --
@ -19,8 +19,8 @@
local DEBUG_MODE = false local DEBUG_MODE = false
flow = {} flow = {}
local S = minetest.get_translator("flow") local S = core.get_translator("flow")
local modpath = minetest.get_modpath("flow") local modpath = core.get_modpath("flow")
local Form = {} local Form = {}
@ -83,7 +83,7 @@ local CHAR_WIDTH = 0.21
local current_lang local current_lang
-- get_translated_string doesn't exist in MT 5.2.0 and older -- get_translated_string doesn't exist in MT 5.2.0 and older
local get_translated_string = minetest.get_translated_string or function(_, s) local get_translated_string = core.get_translated_string or function(_, s)
return s return s
end end
@ -156,6 +156,7 @@ size_getters.button_exit = size_getters.button
size_getters.image_button = size_getters.button size_getters.image_button = size_getters.button
size_getters.image_button_exit = size_getters.button size_getters.image_button_exit = size_getters.button
size_getters.item_image_button = size_getters.button size_getters.item_image_button = size_getters.button
size_getters.button_url = size_getters.button
function size_getters.field(node) function size_getters.field(node)
local label_w, label_h = get_label_size(node.label) local label_w, label_h = get_label_size(node.label)
@ -289,7 +290,7 @@ function size_getters.stack(stack)
end end
function size_getters.padding(node) function size_getters.padding(node)
minetest.log("warning", "[flow] The gui.Padding element is deprecated") core.log("warning", "[flow] The gui.Padding element is deprecated")
assert(#node == 1, "Padding can only have one element inside.") assert(#node == 1, "Padding can only have one element inside.")
local n = node[1] local n = node[1]
local x, y = apply_padding(n, 0, 0) local x, y = apply_padding(n, 0, 0)
@ -365,7 +366,7 @@ function align_types.fill(node, x, w, extra_space)
if node[w] then if node[w] then
node[w] = node[w] + extra_space node[w] = node[w] + extra_space
else else
minetest.log("warning", "[flow] Unknown element: \"" .. core.log("warning", "[flow] Unknown element: \"" ..
tostring(node.type) .. "\". Please make sure that flow is " .. tostring(node.type) .. "\". Please make sure that flow is " ..
"up-to-date and the element has a size set (if required).") "up-to-date and the element has a size set (if required).")
node[w] = extra_space node[w] = extra_space
@ -541,12 +542,12 @@ end
-- Renders the GUI into hopefully valid AST -- Renders the GUI into hopefully valid AST
-- This won't fill in names -- This won't fill in names
local function render_ast(node, embedded) local function render_ast(node, embedded)
local t1 = DEBUG_MODE and minetest.get_us_time() local t1 = DEBUG_MODE and core.get_us_time()
node.padding = node.padding or 0.3 node.padding = node.padding or 0.3
local w, h = apply_padding(node, 0, 0) local w, h = apply_padding(node, 0, 0)
local t2 = DEBUG_MODE and minetest.get_us_time() local t2 = DEBUG_MODE and core.get_us_time()
expand(node) expand(node)
local t3 = DEBUG_MODE and minetest.get_us_time() local t3 = DEBUG_MODE and core.get_us_time()
local res = { local res = {
formspec_version = 7, formspec_version = 7,
{type = "size", w = w, h = h}, {type = "size", w = w, h = h},
@ -589,7 +590,7 @@ local function render_ast(node, embedded)
res[#res + 1] = node res[#res + 1] = node
if DEBUG_MODE then if DEBUG_MODE then
local t4 = minetest.get_us_time() local t4 = core.get_us_time()
print('apply_padding', t2 - t1) print('apply_padding', t2 - t1)
print('expand', t3 - t2) print('expand', t3 - t2)
print('field_close_on_enter', t4 - t3) print('field_close_on_enter', t4 - t3)
@ -627,12 +628,12 @@ local field_value_transformers = {
-- Remove control characters and newlines -- Remove control characters and newlines
return value:gsub("[%z\1-\8\10-\31\127]", ""):gsub(C1_CHARS, "") return value:gsub("[%z\1-\8\10-\31\127]", ""):gsub(C1_CHARS, "")
end), end),
checkbox = simple_transformer(minetest.is_yes), checkbox = simple_transformer(core.is_yes),
-- Scrollbars do have min/max values but scrollbars are only really used by -- Scrollbars do have min/max values but scrollbars are only really used by
-- ScrollableVBox which doesn't need the extra checks -- ScrollableVBox which doesn't need the extra checks
scrollbar = simple_transformer(function(value) scrollbar = simple_transformer(function(value)
return minetest.explode_scrollbar_event(value).value return core.explode_scrollbar_event(value).value
end), end),
} }
@ -653,7 +654,7 @@ function field_value_transformers.dropdown(node, _, formspec_version)
-- value of the dropdown is anyway, we can just enable index_event for new -- value of the dropdown is anyway, we can just enable index_event for new
-- clients and keep the same behaviour -- clients and keep the same behaviour
if (formspec_version and formspec_version >= 4) or if (formspec_version and formspec_version >= 4) or
(minetest.global_exists("fs51") and (core.global_exists("fs51") and
fs51.monkey_patching_enabled) then fs51.monkey_patching_enabled) then
node.index_event = true node.index_event = true
@ -682,7 +683,7 @@ function field_value_transformers.table(node, tablecolumn_count)
local rows = ceil(cells / tablecolumn_count) local rows = ceil(cells / tablecolumn_count)
return function(value) return function(value)
local row = floor(minetest.explode_table_event(value).row) local row = floor(core.explode_table_event(value).row)
-- Tables and textlists can have values of 0 (nothing selected) but I -- Tables and textlists can have values of 0 (nothing selected) but I
-- don't think the client can un-select a row so it should be safe to -- don't think the client can un-select a row so it should be safe to
-- ignore any 0 sent by the client to guarantee that the row will be -- ignore any 0 sent by the client to guarantee that the row will be
@ -696,7 +697,7 @@ end
function field_value_transformers.textlist(node) function field_value_transformers.textlist(node)
local rows = node.listelems and #node.listelems or 0 local rows = node.listelems and #node.listelems or 0
return function(value) return function(value)
local index = floor(minetest.explode_textlist_event(value).index) local index = floor(core.explode_textlist_event(value).index)
if index >= 1 and index <= rows then if index >= 1 and index <= rows then
return index return index
end end
@ -847,7 +848,7 @@ local function parse_callbacks(tree, ctx_form, auto_name_id,
elseif btn_callbacks[node_name] or elseif btn_callbacks[node_name] or
(is_btn and saved_fields[node_name]) or (is_btn and saved_fields[node_name]) or
(callbacks and callbacks[node_name]) then (callbacks and callbacks[node_name]) then
minetest.log("warning", ("[flow] Multiple callbacks have " .. core.log("warning", ("[flow] Multiple callbacks have " ..
"been registered for elements with the same name (%q), " .. "been registered for elements with the same name (%q), " ..
"this will not work properly."):format(node_name)) "this will not work properly."):format(node_name))
@ -899,7 +900,7 @@ local gui_mt = {
} }
local gui = setmetatable({ local gui = setmetatable({
embed = function(fs, w, h) embed = function(fs, w, h)
minetest.log("warning", "[flow] gui.embed() is deprecated") core.log("warning", "[flow] gui.embed() is deprecated")
if type(fs) ~= "table" then if type(fs) ~= "table" then
fs = formspec_ast.parse(fs) fs = formspec_ast.parse(fs)
end end
@ -929,7 +930,7 @@ local function insert_style_elem(tree, idx, node, props, sels)
if suffix then if suffix then
selectors[i] = base_selector .. ":" .. suffix selectors[i] = base_selector .. ":" .. suffix
else else
minetest.log("warning", "[flow] Invalid style selector: " .. core.log("warning", "[flow] Invalid style selector: " ..
tostring(sel)) tostring(sel))
end end
end end
@ -1097,15 +1098,15 @@ end
local function prepare_form(self, player, formname, ctx, auto_name_id) local function prepare_form(self, player, formname, ctx, auto_name_id)
local name = player:get_player_name() local name = player:get_player_name()
-- local t = DEBUG_MODE and minetest.get_us_time() -- local t = DEBUG_MODE and core.get_us_time()
local info = minetest.get_player_information(name) local info = core.get_player_information(name)
local tree, form_info = self:_render(player, ctx, local tree, form_info = self:_render(player, ctx,
info and info.formspec_version, auto_name_id, false, info and info.formspec_version, auto_name_id, false,
info and info.lang_code) info and info.lang_code)
-- local t2 = DEBUG_MODE and minetest.get_us_time() -- local t2 = DEBUG_MODE and core.get_us_time()
local fs = assert(formspec_ast.unparse(tree)) local fs = assert(formspec_ast.unparse(tree))
-- local t3 = DEBUG_MODE and minetest.get_us_time() -- local t3 = DEBUG_MODE and core.get_us_time()
form_info.formname = formname form_info.formname = formname
-- if DEBUG_MODE then -- if DEBUG_MODE then
@ -1121,15 +1122,15 @@ local function show_form(self, player, formname, ctx, auto_name_id)
auto_name_id) auto_name_id)
open_formspecs[name] = form_info open_formspecs[name] = form_info
minetest.show_formspec(name, formname, fs) core.show_formspec(name, formname, fs)
end end
local next_formname = 0 local next_formname = 0
function Form:show(player, ctx) function Form:show(player, ctx)
if type(player) == "string" then if type(player) == "string" then
minetest.log("warning", core.log("warning",
"[flow] Calling form:show() with a player name is deprecated") "[flow] Calling form:show() with a player name is deprecated")
player = minetest.get_player_by_name(player) player = core.get_player_by_name(player)
if not player then return end if not player then return end
end end
@ -1142,7 +1143,7 @@ function Form:show(player, ctx)
end end
function Form:show_hud(player, ctx) function Form:show_hud(player, ctx)
local info = minetest.get_player_information(player:get_player_name()) local info = core.get_player_information(player:get_player_name())
local tree = self:_render(player, ctx or {}, nil, nil, nil, local tree = self:_render(player, ctx or {}, nil, nil, nil,
info and info.lang_code) info and info.lang_code)
hud_fs.show_hud(player, self, tree) hud_fs.show_hud(player, self, tree)
@ -1177,7 +1178,7 @@ local render_to_formspec_auto_name_ids = {}
-- target formspec version -- target formspec version
function Form:render_to_formspec_string(player, ctx, standalone) function Form:render_to_formspec_string(player, ctx, standalone)
local name = player:get_player_name() local name = player:get_player_name()
local info = minetest.get_player_information(name) local info = core.get_player_information(name)
local tree, form_info = self:_render(player, ctx or {}, local tree, form_info = self:_render(player, ctx or {},
info and info.formspec_version, render_to_formspec_auto_name_ids[name], info and info.formspec_version, render_to_formspec_auto_name_ids[name],
not standalone, info and info.lang_code) not standalone, info and info.lang_code)
@ -1194,9 +1195,9 @@ function Form:render_to_formspec_string(player, ctx, standalone)
-- Just in case the player goes offline, we should not keep the player -- Just in case the player goes offline, we should not keep the player
-- reference. Nothing prevents the user from calling this function when -- reference. Nothing prevents the user from calling this function when
-- the player is offline, unlike the _real_ formspec submission. -- the player is offline, unlike the _real_ formspec submission.
local player = minetest.get_player_by_name(name) local player = core.get_player_by_name(name)
if not player then if not player then
minetest.log("warning", "[flow] Player " .. name .. core.log("warning", "[flow] Player " .. name ..
" was offline when render_to_formspec_string event was" .. " was offline when render_to_formspec_string event was" ..
" triggered. Events were not passed through.") " triggered. Events were not passed through.")
return nil return nil
@ -1211,7 +1212,7 @@ function Form:close(player)
local form_info = open_formspecs[name] local form_info = open_formspecs[name]
if form_info and form_info.self == self then if form_info and form_info.self == self then
open_formspecs[name] = nil open_formspecs[name] = nil
minetest.close_formspec(name, form_info.formname) core.close_formspec(name, form_info.formname)
end end
end end
@ -1228,7 +1229,7 @@ function Form:unset_as_inventory_for(player)
end end
end end
-- This function may eventually call minetest.update_formspec if/when it gets -- This function may eventually call core.update_formspec if/when it gets
-- added (https://github.com/minetest/minetest/issues/13142) -- added (https://github.com/minetest/minetest/issues/13142)
local function update_form(self, player, form_info) local function update_form(self, player, form_info)
show_form(self, player, form_info.formname, form_info.ctx, show_form(self, player, form_info.formname, form_info.ctx,
@ -1245,7 +1246,7 @@ end
function Form:update_where(func) function Form:update_where(func)
for name, form_info in pairs(open_formspecs) do for name, form_info in pairs(open_formspecs) do
if form_info.self == self then if form_info.self == self then
local player = minetest.get_player_by_name(name) local player = core.get_player_by_name(name)
if player and func(player, form_info.ctx) then if player and func(player, form_info.ctx) then
update_form(self, player, form_info) update_form(self, player, form_info)
end end
@ -1281,7 +1282,7 @@ function fs_process_events(player, form_info, fields)
-- potential to break things. Please open an issue if you -- potential to break things. Please open an issue if you
-- (somehow) need to use longer text in fields. -- (somehow) need to use longer text in fields.
local name = player:get_player_name() local name = player:get_player_name()
minetest.log("warning", "[flow] Player " .. name .. " tried" .. core.log("warning", "[flow] Player " .. name .. " tried" ..
" submitting a large field value (>60 kB), ignoring.") " submitting a large field value (>60 kB), ignoring.")
else else
local new_value = transformer(raw_value) local new_value = transformer(raw_value)
@ -1327,7 +1328,7 @@ function fs_process_events(player, form_info, fields)
return redraw_fs return redraw_fs
end end
minetest.register_on_player_receive_fields(function(player, formname, fields) core.register_on_player_receive_fields(function(player, formname, fields)
local name = player:get_player_name() local name = player:get_player_name()
local form_infos = formname == "" and open_inv_formspecs or open_formspecs local form_infos = formname == "" and open_inv_formspecs or open_formspecs
local form_info = form_infos[name] local form_info = form_infos[name]
@ -1350,7 +1351,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
return true return true
end) end)
minetest.register_on_leaveplayer(function(player) core.register_on_leaveplayer(function(player)
local name = player:get_player_name() local name = player:get_player_name()
open_formspecs[name] = nil open_formspecs[name] = nil
open_inv_formspecs[name] = nil open_inv_formspecs[name] = nil
@ -1537,9 +1538,9 @@ function gui_mt.__newindex()
error("Cannot modifiy gui table") error("Cannot modifiy gui table")
end end
if minetest.is_singleplayer() then if core.is_singleplayer() then
local example_form local example_form
minetest.register_chatcommand("flow-example", { core.register_chatcommand("flow-example", {
privs = {server = true}, privs = {server = true},
help = S"Shows an example form", help = S"Shows an example form",
func = function(name) func = function(name)
@ -1547,7 +1548,7 @@ if minetest.is_singleplayer() then
if not example_form then if not example_form then
example_form = dofile(modpath .. "/example.lua") example_form = dofile(modpath .. "/example.lua")
end end
example_form:show(minetest.get_player_by_name(name)) example_form:show(core.get_player_by_name(name))
end, end,
}) })
end end
@ -1557,5 +1558,5 @@ if DEBUG_MODE then
if f then if f then
return f() return f()
end end
minetest.log("error", "[flow] " .. tostring(err)) core.log("error", "[flow] " .. tostring(err))
end end

View File

@ -1,5 +1,5 @@
-- --
-- Minetest formspec layout engine -- Luanti formspec layout engine
-- --
-- Copyright © 2022 by luk3yx -- Copyright © 2022 by luk3yx
-- --
@ -24,26 +24,26 @@ _G.FORMSPEC_AST_PATH = '../formspec_ast'
dofile(FORMSPEC_AST_PATH .. '/init.lua') dofile(FORMSPEC_AST_PATH .. '/init.lua')
-- Stub Minetest API -- Stub Minetest API
_G.minetest = {} _G.core = {}
function minetest.is_yes(str) function core.is_yes(str)
str = str:lower() str = str:lower()
return str == "true" or str == "yes" return str == "true" or str == "yes"
end end
local callback local callback
function minetest.register_on_player_receive_fields(func) function core.register_on_player_receive_fields(func)
assert(callback == nil) assert(callback == nil)
callback = func callback = func
end end
local function dummy() end local function dummy() end
minetest.register_on_leaveplayer = dummy core.register_on_leaveplayer = dummy
minetest.is_singleplayer = dummy core.is_singleplayer = dummy
minetest.get_player_information = dummy core.get_player_information = dummy
minetest.show_formspec = dummy core.show_formspec = dummy
function minetest.get_modpath(modname) function core.get_modpath(modname)
if modname == "flow" then if modname == "flow" then
return "." return "."
elseif modname == "formspec_ast" then elseif modname == "formspec_ast" then
@ -51,7 +51,7 @@ function minetest.get_modpath(modname)
end end
end end
function minetest.get_translator(modname) function core.get_translator(modname)
assert(modname == "flow") assert(modname == "flow")
return function(str) return str end return function(str) return str end
end end
@ -72,7 +72,7 @@ local function stub_player(name)
return formspec return formspec
end end
end end
function minetest.get_player_by_name(passed_in_name) function core.get_player_by_name(passed_in_name)
assert(name == passed_in_name) assert(name == passed_in_name)
return self return self
end end
@ -99,21 +99,21 @@ string.split = string.split or function(str, chr)
return r return r
end end
function minetest.explode_textlist_event(event) function core.explode_textlist_event(event)
local event_type, number = event:match("^([A-Z]+):(%d+)$") local event_type, number = event:match("^([A-Z]+):(%d+)$")
return {type = event_type, index = tonumber(number) or 0} return {type = event_type, index = tonumber(number) or 0}
end end
function minetest.explode_table_event(event) function core.explode_table_event(event)
local event_type, row, column = event:match("^([A-Z]+):(%d+):(%d+)$") local event_type, row, column = event:match("^([A-Z]+):(%d+):(%d+)$")
return {type = event_type, row = tonumber(row) or 0, column = tonumber(column) or 0} return {type = event_type, row = tonumber(row) or 0, column = tonumber(column) or 0}
end end
function minetest.global_exists(var) function core.global_exists(var)
return rawget(_G, var) ~= nil return rawget(_G, var) ~= nil
end end
function minetest.get_player_information(name) function core.get_player_information(name)
return name == "fs6" and {formspec_version = 6} or nil return name == "fs6" and {formspec_version = 6} or nil
end end
@ -519,7 +519,7 @@ describe("Flow", function()
assert.equals(manual_spy[1], player, "player was first arg") assert.equals(manual_spy[1], player, "player was first arg")
assert.equals(manual_spy[2], ctx, "context was next") assert.equals(manual_spy[2], ctx, "context was next")
minetest.get_player_by_name = nil core.get_player_by_name = nil
end) end)
end) end)