FormSpec: Add list spacing, slot size, and noclip (#10083)

* Add list spacing, slot size, and noclip

* Simplify StyleSpec

* Add test cases

Co-authored-by: rubenwardy <rw@rubenwardy.com>
This commit is contained in:
Vincent Robinson 2021-01-23 12:46:19 -08:00 committed by GitHub
parent 4c76239818
commit 009e39e73b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 78 additions and 22 deletions

@ -2226,7 +2226,8 @@ Elements
* Show an inventory list if it has been sent to the client. Nothing will * Show an inventory list if it has been sent to the client. Nothing will
be shown if the inventory list is of size 0. be shown if the inventory list is of size 0.
* **Note**: With the new coordinate system, the spacing between inventory * **Note**: With the new coordinate system, the spacing between inventory
slots is one-fourth the size of an inventory slot. slots is one-fourth the size of an inventory slot by default. Also see
[Styling Formspecs] for changing the size of slots and spacing.
### `list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;<starting item index>]` ### `list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;<starting item index>]`
@ -2809,6 +2810,7 @@ Some types may inherit styles from parent types.
* image_button * image_button
* item_image_button * item_image_button
* label * label
* list
* model * model
* pwdfield, inherits from field * pwdfield, inherits from field
* scrollbar * scrollbar
@ -2896,6 +2898,10 @@ Some types may inherit styles from parent types.
* font - Sets font type. See button `font` property for more information. * font - Sets font type. See button `font` property for more information.
* font_size - Sets font size. See button `font_size` property for more information. * font_size - Sets font size. See button `font_size` property for more information.
* noclip - boolean, set to true to allow the element to exceed formspec bounds. * noclip - boolean, set to true to allow the element to exceed formspec bounds.
* list
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* size - 2d vector, sets the size of inventory slots in coordinates.
* spacing - 2d vector, sets the space between inventory slots in coordinates.
* image_button (additional properties) * image_button (additional properties)
* fgimg - standard image. Defaults to none. * fgimg - standard image. Defaults to none.
* fgimg_hovered - image when hovered. Defaults to fgimg when not provided. * fgimg_hovered - image when hovered. Defaults to fgimg when not provided.

@ -33,6 +33,15 @@ local tabheaders_fs = [[
tabheader[8,6;10,1.5;tabs_size2;Height=1.5;1;false;false] tabheader[8,6;10,1.5;tabs_size2;Height=1.5;1;false;false]
]] ]]
local inv_style_fs = [[
style_type[list;noclip=true]
list[current_player;main;-1.125,-1.125;2,2]
style_type[list;spacing=.25,.125;size=.75,.875]
list[current_player;main;3,.5;3,3]
style_type[list;spacing=0;size=1]
list[current_player;main;.5,4;8,4]
]]
local hypertext_basic = [[ local hypertext_basic = [[
<bigger>Normal test</bigger> <bigger>Normal test</bigger>
This is a normal text. This is a normal text.
@ -310,6 +319,10 @@ local pages = {
"size[12,13]real_coordinates[true]" .. "size[12,13]real_coordinates[true]" ..
"container[0.5,1.5]" .. tabheaders_fs .. "container_end[]", "container[0.5,1.5]" .. tabheaders_fs .. "container_end[]",
-- Inv
"size[12,13]real_coordinates[true]" ..
"container[0.5,1.5]" .. inv_style_fs .. "container_end[]",
-- Animation -- Animation
[[ [[
formspec_version[3] formspec_version[3]
@ -341,7 +354,7 @@ Number]
local function show_test_formspec(pname, page_id) local function show_test_formspec(pname, page_id)
page_id = page_id or 2 page_id = page_id or 2
local fs = pages[page_id] .. "tabheader[0,0;8,0.65;maintabs;Real Coord,Styles,Noclip,Hypertext,Tabs,Anim,ScrollC;" .. page_id .. ";false;false]" local fs = pages[page_id] .. "tabheader[0,0;8,0.65;maintabs;Real Coord,Styles,Noclip,Hypertext,Tabs,Invs,Anim,ScrollC;" .. page_id .. ";false;false]"
minetest.show_formspec(pname, "testformspec:formspec", fs) minetest.show_formspec(pname, "testformspec:formspec", fs)
end end

@ -55,6 +55,8 @@ public:
BORDERCOLORS, BORDERCOLORS,
BORDERWIDTHS, BORDERWIDTHS,
SOUND, SOUND,
SPACING,
SIZE,
NUM_PROPERTIES, NUM_PROPERTIES,
NONE NONE
}; };
@ -119,6 +121,10 @@ public:
return BORDERWIDTHS; return BORDERWIDTHS;
} else if (name == "sound") { } else if (name == "sound") {
return SOUND; return SOUND;
} else if (name == "spacing") {
return SPACING;
} else if (name == "size") {
return SIZE;
} else { } else {
return NONE; return NONE;
} }
@ -259,27 +265,40 @@ public:
return rect; return rect;
} }
irr::core::vector2d<s32> getVector2i(Property prop, irr::core::vector2d<s32> def) const v2f32 getVector2f(Property prop, v2f32 def) const
{ {
const auto &val = properties[prop]; const auto &val = properties[prop];
if (val.empty()) if (val.empty())
return def; return def;
irr::core::vector2d<s32> vec; v2f32 vec;
if (!parseVector2i(val, &vec)) if (!parseVector2f(val, &vec))
return def; return def;
return vec; return vec;
} }
irr::core::vector2d<s32> getVector2i(Property prop) const v2s32 getVector2i(Property prop, v2s32 def) const
{
const auto &val = properties[prop];
if (val.empty())
return def;
v2f32 vec;
if (!parseVector2f(val, &vec))
return def;
return v2s32(vec.X, vec.Y);
}
v2s32 getVector2i(Property prop) const
{ {
const auto &val = properties[prop]; const auto &val = properties[prop];
FATAL_ERROR_IF(val.empty(), "Unexpected missing property"); FATAL_ERROR_IF(val.empty(), "Unexpected missing property");
irr::core::vector2d<s32> vec; v2f32 vec;
parseVector2i(val, &vec); parseVector2f(val, &vec);
return vec; return v2s32(vec.X, vec.Y);
} }
gui::IGUIFont *getFont() const gui::IGUIFont *getFont() const
@ -432,22 +451,20 @@ private:
return true; return true;
} }
bool parseVector2i(const std::string &value, irr::core::vector2d<s32> *parsed_vec) const bool parseVector2f(const std::string &value, v2f32 *parsed_vec) const
{ {
irr::core::vector2d<s32> vec; v2f32 vec;
std::vector<std::string> v_vector = split(value, ','); std::vector<std::string> v_vector = split(value, ',');
if (v_vector.size() == 1) { if (v_vector.size() == 1) {
s32 x = stoi(v_vector[0]); f32 x = stof(v_vector[0]);
vec.X = x; vec.X = x;
vec.Y = x; vec.Y = x;
} else if (v_vector.size() == 2) { } else if (v_vector.size() == 2) {
s32 x = stoi(v_vector[0]); vec.X = stof(v_vector[0]);
s32 y = stoi(v_vector[1]); vec.Y = stof(v_vector[1]);
vec.X = x;
vec.Y = y;
} else { } else {
warningstream << "Invalid vector2d string format: \"" << value warningstream << "Invalid 2d vector string format: \"" << value
<< "\"" << std::endl; << "\"" << std::endl;
return false; return false;
} }

@ -497,20 +497,40 @@ void GUIFormSpecMenu::parseList(parserData *data, const std::string &element)
3 3
); );
v2f32 slot_spacing = data->real_coordinates ? auto style = getDefaultStyleForElement("list", spec.fname);
v2f32(imgsize.X * 1.25f, imgsize.Y * 1.25f) : spacing;
v2s32 pos = data->real_coordinates ? getRealCoordinateBasePos(v_pos) v2f32 slot_scale = style.getVector2f(StyleSpec::SIZE, v2f32(0, 0));
: getElementBasePos(&v_pos); v2s32 slot_size(
slot_scale.X <= 0 ? imgsize.X : slot_scale.X * imgsize.X,
slot_scale.Y <= 0 ? imgsize.Y : slot_scale.Y * imgsize.Y
);
v2f32 slot_spacing = style.getVector2f(StyleSpec::SPACING, v2f32(-1, -1));
if (data->real_coordinates) {
slot_spacing.X = slot_spacing.X < 0 ? imgsize.X * 1.25f :
slot_spacing.X * imgsize.X + imgsize.X;
slot_spacing.Y = slot_spacing.Y < 0 ? imgsize.Y * 1.25f :
slot_spacing.Y * imgsize.Y + imgsize.Y;
} else {
slot_spacing.X = slot_spacing.X < 0 ? spacing.X :
slot_spacing.X * spacing.X;
slot_spacing.Y = slot_spacing.Y < 0 ? spacing.Y :
slot_spacing.Y * spacing.Y;
}
v2s32 pos = data->real_coordinates ? getRealCoordinateBasePos(v_pos) :
getElementBasePos(&v_pos);
core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y,
pos.X + (geom.X - 1) * slot_spacing.X + imgsize.X, pos.X + (geom.X - 1) * slot_spacing.X + imgsize.X,
pos.Y + (geom.Y - 1) * slot_spacing.Y + imgsize.Y); pos.Y + (geom.Y - 1) * slot_spacing.Y + imgsize.Y);
GUIInventoryList *e = new GUIInventoryList(Environment, data->current_parent, GUIInventoryList *e = new GUIInventoryList(Environment, data->current_parent,
spec.fid, rect, m_invmgr, loc, listname, geom, start_i, imgsize, spec.fid, rect, m_invmgr, loc, listname, geom, start_i, slot_size,
slot_spacing, this, data->inventorylist_options, m_font); slot_spacing, this, data->inventorylist_options, m_font);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
m_inventorylists.push_back(e); m_inventorylists.push_back(e);
m_fields.push_back(spec); m_fields.push_back(spec);
return; return;