forked from your-land-mirror/minetest-flow
Luanti rename, add ButtonURL support
This commit is contained in:
parent
136f2b1637
commit
f306f01f57
@ -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'}}
|
||||||
}
|
}
|
||||||
|
20
README.md
20
README.md
@ -1,8 +1,8 @@
|
|||||||
# flow
|
# flow
|
||||||
|
|
||||||
[](https://content.minetest.net/packages/luk3yx/flow/)
|
[](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.
|
||||||
|
|
||||||
|
78
elements.md
78
elements.md
@ -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
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--
|
--
|
||||||
-- Minetest formspec layout engine
|
-- Luanti formspec layout engine
|
||||||
--
|
--
|
||||||
-- Copyright © 2022 by luk3yx
|
-- Copyright © 2022 by luk3yx
|
||||||
--
|
--
|
||||||
|
@ -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
|
||||||
|
@ -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}{{'
|
||||||
|
79
init.lua
79
init.lua
@ -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
|
||||||
|
32
test.lua
32
test.lua
@ -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)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user