Skip to content

Commit

Permalink
Add padding[] element to formspecs (#11821)
Browse files Browse the repository at this point in the history
  • Loading branch information
v-rob committed Dec 30, 2021
1 parent 4a16ab3 commit 544b9d5
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 24 deletions.
17 changes: 14 additions & 3 deletions doc/lua_api.txt
Expand Up @@ -117,7 +117,7 @@ Menu music
-----------

Games can provide custom main menu music. They are put inside a `menu`
directory inside the game directory.
directory inside the game directory.

The music files are named `theme.ogg`.
If you want to specify multiple music files for one game, add additional
Expand Down Expand Up @@ -2326,9 +2326,20 @@ Elements
* `position` and `anchor` elements need suitable values to avoid a formspec
extending off the game window due to particular game window sizes.

### `no_prepend[]`
### `padding[<X>,<Y>]`

* Must be used after the `size`, `position`, and `anchor` elements (if present).
* Defines how much space is padded around the formspec if the formspec tries to
increase past the size of the screen and coordinates have to be shrunk.
* For X and Y, 0.0 represents no padding (the formspec can touch the edge of the
screen), and 0.5 represents half the screen (which forces the coordinate size
to 0). If negative, the formspec can extend off the edge of the screen.
* Defaults to [0.05, 0.05].

### `no_prepend[]`

* Must be used after the `size`, `position`, `anchor`, and `padding` elements
(if present).
* Disables player:set_formspec_prepend() from applying to this formspec.

### `real_coordinates[<bool>]`
Expand Down Expand Up @@ -7915,7 +7926,7 @@ Used by `minetest.register_node`.
items = {"default:sand", "default:desert_sand"},
},
{
-- Only drop if using an item in the "magicwand" group, or
-- Only drop if using an item in the "magicwand" group, or
-- an item that is in both the "pickaxe" and the "lucky"
-- groups.
tool_groups = {
Expand Down
65 changes: 59 additions & 6 deletions games/devtest/mods/testformspec/formspec.lua
Expand Up @@ -270,6 +270,16 @@ local scroll_fs =
--style_type[label;border=;bgcolor=]
--label[0.75,2;Reset]

local window = {
sizex = 12,
sizey = 13,
positionx = 0.5,
positiony = 0.5,
anchorx = 0.5,
anchory = 0.5,
paddingx = 0.05,
paddingy = 0.05
}

local pages = {
-- Real Coordinates
Expand Down Expand Up @@ -341,9 +351,28 @@ local pages = {
"size[12,13]real_coordinates[true]" ..
"container[0.5,1.5]" .. tabheaders_fs .. "container_end[]",

-- Inv
-- Inv
"size[12,13]real_coordinates[true]" .. inv_style_fs,

-- Window
function()
return "formspec_version[3]" ..
string.format("size[%s,%s]position[%s,%s]anchor[%s,%s]padding[%s,%s]",
window.sizex, window.sizey, window.positionx, window.positiony,
window.anchorx, window.anchory, window.paddingx, window.paddingy) ..
string.format("field[0.5,0.5;2.5,0.5;sizex;X Size;%s]field[3.5,0.5;2.5,0.5;sizey;Y Size;%s]" ..
"field[0.5,1.5;2.5,0.5;positionx;X Position;%s]field[3.5,1.5;2.5,0.5;positiony;Y Position;%s]" ..
"field[0.5,2.5;2.5,0.5;anchorx;X Anchor;%s]field[3.5,2.5;2.5,0.5;anchory;Y Anchor;%s]" ..
"field[0.5,3.5;2.5,0.5;paddingx;X Padding;%s]field[3.5,3.5;2.5,0.5;paddingy;Y Padding;%s]" ..
"button[2,4.5;2.5,0.5;submit_window;Submit]",
window.sizex, window.sizey, window.positionx, window.positiony,
window.anchorx, window.anchory, window.paddingx, window.paddingy) ..
"field_close_on_enter[sizex;false]field_close_on_enter[sizey;false]" ..
"field_close_on_enter[positionx;false]field_close_on_enter[positiony;false]" ..
"field_close_on_enter[anchorx;false]field_close_on_enter[anchory;false]" ..
"field_close_on_enter[paddingx;false]field_close_on_enter[paddingy;false]"
end,

-- Animation
[[
formspec_version[3]
Expand Down Expand Up @@ -403,10 +432,14 @@ mouse control = true]
]],
}

local function show_test_formspec(pname, page_id)
page_id = page_id or 2
local page_id = 2
local function show_test_formspec(pname)
local page = pages[page_id]
if type(page) == "function" then
page = page()
end

local fs = pages[page_id] .. "tabheader[0,0;8,0.65;maintabs;Real Coord,Styles,Noclip,Hypertext,Tabs,Invs,Anim,Model,ScrollC,Sound;" .. page_id .. ";false;false]"
local fs = page .. "tabheader[0,0;8,0.65;maintabs;Real Coord,Styles,Noclip,Hypertext,Tabs,Invs,Window,Anim,Model,ScrollC,Sound;" .. page_id .. ";false;false]"

minetest.show_formspec(pname, "testformspec:formspec", fs)
end
Expand All @@ -416,9 +449,9 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
return false
end


if fields.maintabs then
show_test_formspec(player:get_player_name(), tonumber(fields.maintabs))
page_id = tonumber(fields.maintabs)
show_test_formspec(player:get_player_name())
return true
end

Expand All @@ -434,6 +467,26 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
minetest.chat_send_player(player:get_player_name(), "Hypertext action received: " .. tostring(fields.hypertext))
return true
end

for name, value in pairs(fields) do
if window[name] then
print(name, window[name])
local num_val = tonumber(value) or 0

if name == "sizex" and num_val < 4 then
num_val = 6.5
elseif name == "sizey" and num_val < 5 then
num_val = 5.5
end

window[name] = num_val
print(name, window[name])
end
end

if fields.submit_window then
show_test_formspec(player:get_player_name())
end
end)

minetest.register_chatcommand("test_formspec", {
Expand Down
88 changes: 73 additions & 15 deletions src/gui/guiFormSpecMenu.cpp
Expand Up @@ -2470,11 +2470,16 @@ bool GUIFormSpecMenu::parsePositionDirect(parserData *data, const std::string &e

void GUIFormSpecMenu::parsePosition(parserData *data, const std::string &element)
{
std::vector<std::string> parts = split(element, ',');
std::vector<std::string> parts = split(element, ';');

if (parts.size() == 2) {
data->offset.X = stof(parts[0]);
data->offset.Y = stof(parts[1]);
if (parts.size() == 1 ||
(parts.size() > 1 && m_formspec_version > FORMSPEC_API_VERSION)) {
std::vector<std::string> v_geom = split(parts[0], ',');

MY_CHECKGEOM("position", 0);

data->offset.X = stof(v_geom[0]);
data->offset.Y = stof(v_geom[1]);
return;
}

Expand Down Expand Up @@ -2504,18 +2509,63 @@ bool GUIFormSpecMenu::parseAnchorDirect(parserData *data, const std::string &ele

void GUIFormSpecMenu::parseAnchor(parserData *data, const std::string &element)
{
std::vector<std::string> parts = split(element, ',');
std::vector<std::string> parts = split(element, ';');

if (parts.size() == 2) {
data->anchor.X = stof(parts[0]);
data->anchor.Y = stof(parts[1]);
if (parts.size() == 1 ||
(parts.size() > 1 && m_formspec_version > FORMSPEC_API_VERSION)) {
std::vector<std::string> v_geom = split(parts[0], ',');

MY_CHECKGEOM("anchor", 0);

data->anchor.X = stof(v_geom[0]);
data->anchor.Y = stof(v_geom[1]);
return;
}

errorstream << "Invalid anchor element (" << parts.size() << "): '" << element
<< "'" << std::endl;
}

bool GUIFormSpecMenu::parsePaddingDirect(parserData *data, const std::string &element)
{
if (element.empty())
return false;

std::vector<std::string> parts = split(element, '[');

if (parts.size() != 2)
return false;

std::string type = trim(parts[0]);
std::string description = trim(parts[1]);

if (type != "padding")
return false;

parsePadding(data, description);

return true;
}

void GUIFormSpecMenu::parsePadding(parserData *data, const std::string &element)
{
std::vector<std::string> parts = split(element, ';');

if (parts.size() == 1 ||
(parts.size() > 1 && m_formspec_version > FORMSPEC_API_VERSION)) {
std::vector<std::string> v_geom = split(parts[0], ',');

MY_CHECKGEOM("padding", 0);

data->padding.X = stof(v_geom[0]);
data->padding.Y = stof(v_geom[1]);
return;
}

errorstream << "Invalid padding element (" << parts.size() << "): '" << element
<< "'" << std::endl;
}

bool GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element, bool style_type)
{
std::vector<std::string> parts = split(element, ';');
Expand Down Expand Up @@ -3022,6 +3072,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
mydata.screensize = screensize;
mydata.offset = v2f32(0.5f, 0.5f);
mydata.anchor = v2f32(0.5f, 0.5f);
mydata.padding = v2f32(0.05f, 0.05f);
mydata.simple_field_count = 0;

// Base position of contents of form
Expand Down Expand Up @@ -3124,7 +3175,14 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
}
}

/* "no_prepend" element is always after "position" (or "size" element) if it used */
/* "padding" element is always after "anchor" and previous if it is used */
for (; i < elements.size(); i++) {
if (!parsePaddingDirect(&mydata, elements[i])) {
break;
}
}

/* "no_prepend" element is always after "padding" and previous if it used */
bool enable_prepends = true;
for (; i < elements.size(); i++) {
if (elements[i].empty())
Expand Down Expand Up @@ -3189,11 +3247,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
double fitx_imgsize;
double fity_imgsize;

// Pad the screensize with 5% of the screensize on all sides to ensure
// that even the largest formspecs don't touch the screen borders.
v2f padded_screensize(
mydata.screensize.X * 0.9f,
mydata.screensize.Y * 0.9f
mydata.screensize.X * (1.0f - mydata.padding.X * 2.0f),
mydata.screensize.Y * (1.0f - mydata.padding.Y * 2.0f)
);

if (mydata.real_coordinates) {
Expand All @@ -3209,13 +3265,15 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
((15.0 / 13.0) * (0.85 + mydata.invsize.Y));
}

s32 min_screen_dim = std::min(mydata.screensize.X, mydata.screensize.Y);

#ifdef HAVE_TOUCHSCREENGUI
// In Android, the preferred imgsize should be larger to accommodate the
// smaller screensize.
double prefer_imgsize = padded_screensize.Y / 10 * gui_scaling;
double prefer_imgsize = min_screen_dim / 10 * gui_scaling;
#else
// Desktop computers have more space, so try to fit 15 coordinates.
double prefer_imgsize = padded_screensize.Y / 15 * gui_scaling;
double prefer_imgsize = min_screen_dim / 15 * gui_scaling;
#endif
// Try to use the preferred imgsize, but if that's bigger than the maximum
// size, use the maximum size.
Expand Down
3 changes: 3 additions & 0 deletions src/gui/guiFormSpecMenu.h
Expand Up @@ -368,6 +368,7 @@ class GUIFormSpecMenu : public GUIModalMenu
v2s32 size;
v2f32 offset;
v2f32 anchor;
v2f32 padding;
core::rect<s32> rect;
v2s32 basepos;
v2u32 screensize;
Expand Down Expand Up @@ -449,6 +450,8 @@ class GUIFormSpecMenu : public GUIModalMenu
void parsePosition(parserData *data, const std::string &element);
bool parseAnchorDirect(parserData *data, const std::string &element);
void parseAnchor(parserData *data, const std::string &element);
bool parsePaddingDirect(parserData *data, const std::string &element);
void parsePadding(parserData *data, const std::string &element);
bool parseStyle(parserData *data, const std::string &element, bool style_type);
void parseSetFocus(const std::string &element);
void parseModel(parserData *data, const std::string &element);
Expand Down

0 comments on commit 544b9d5

Please sign in to comment.