Skip to content

Commit

Permalink
Formspec: allow lists to change size and existence while the formspec…
Browse files Browse the repository at this point in the history
… is open (#9700)

Fixes #9640.
  • Loading branch information
Desour committed Apr 18, 2020
1 parent 241bf44 commit 4fb6b6a
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 41 deletions.
30 changes: 1 addition & 29 deletions src/gui/guiFormSpecMenu.cpp
Expand Up @@ -489,38 +489,10 @@ void GUIFormSpecMenu::parseList(parserData *data, const std::string &element)
start_i = stoi(startindex);

if (geom.X < 0 || geom.Y < 0 || start_i < 0) {
errorstream<< "Invalid list element: '" << element << "'" << std::endl;
errorstream << "Invalid list element: '" << element << "'" << std::endl;
return;
}

// check for the existence of inventory and list
Inventory *inv = m_invmgr->getInventory(loc);
if (!inv) {
warningstream << "GUIFormSpecMenu::parseList(): "
<< "The inventory location "
<< "\"" << loc.dump() << "\" doesn't exist"
<< std::endl;
return;
}
InventoryList *ilist = inv->getList(listname);
if (!ilist) {
warningstream << "GUIFormSpecMenu::parseList(): "
<< "The inventory list \"" << listname << "\" "
<< "@ \"" << loc.dump() << "\" doesn't exist"
<< std::endl;
return;
}

// trim geom if it is larger than the actual inventory size
s32 list_size = (s32)ilist->getSize();
if (list_size < geom.X * geom.Y + start_i) {
list_size -= MYMAX(start_i, 0);
geom.Y = list_size / geom.X;
geom.Y += list_size % geom.X > 0 ? 1 : 0;
if (geom.Y <= 1)
geom.X = list_size;
}

if (!data->explicit_size)
warningstream << "invalid use of list without a size[] element" << std::endl;

Expand Down
42 changes: 31 additions & 11 deletions src/gui/guiInventoryList.cpp
Expand Up @@ -47,7 +47,8 @@ GUIInventoryList::GUIInventoryList(gui::IGUIEnvironment *env,
m_fs_menu(fs_menu),
m_options(options),
m_font(font),
m_hovered_i(-1)
m_hovered_i(-1),
m_already_warned(false)
{
}

Expand All @@ -58,20 +59,27 @@ void GUIInventoryList::draw()

Inventory *inv = m_invmgr->getInventory(m_inventoryloc);
if (!inv) {
warningstream << "GUIInventoryList::draw(): "
<< "The inventory location "
<< "\"" << m_inventoryloc.dump() << "\" doesn't exist anymore"
<< std::endl;
if (!m_already_warned) {
warningstream << "GUIInventoryList::draw(): "
<< "The inventory location "
<< "\"" << m_inventoryloc.dump() << "\" doesn't exist"
<< std::endl;
m_already_warned = true;
}
return;
}
InventoryList *ilist = inv->getList(m_listname);
if (!ilist) {
warningstream << "GUIInventoryList::draw(): "
<< "The inventory list \"" << m_listname << "\" @ \""
<< m_inventoryloc.dump() << "\" doesn't exist anymore"
<< std::endl;
if (!m_already_warned) {
warningstream << "GUIInventoryList::draw(): "
<< "The inventory list \"" << m_listname << "\" @ \""
<< m_inventoryloc.dump() << "\" doesn't exist"
<< std::endl;
m_already_warned = true;
}
return;
}
m_already_warned = false;

video::IVideoDriver *driver = Environment->getVideoDriver();
Client *client = m_fs_menu->getClient();
Expand All @@ -80,9 +88,11 @@ void GUIInventoryList::draw()
core::rect<s32> imgrect(0, 0, m_slot_size.X, m_slot_size.Y);
v2s32 base_pos = AbsoluteRect.UpperLeftCorner;

const s32 list_size = (s32)ilist->getSize();

for (s32 i = 0; i < m_geom.X * m_geom.Y; i++) {
s32 item_i = i + m_start_item_i;
if (item_i >= (s32)ilist->getSize())
if (item_i >= list_size)
break;

v2s32 p((i % m_geom.X) * m_slot_spacing.X,
Expand Down Expand Up @@ -192,10 +202,19 @@ bool GUIInventoryList::OnEvent(const SEvent &event)

s32 GUIInventoryList::getItemIndexAtPos(v2s32 p) const
{
// no item if no gui element at pointer
if (!IsVisible || AbsoluteClippingRect.getArea() <= 0 ||
!AbsoluteClippingRect.isPointInside(p))
return -1;

// there can not be an item if the inventory or the inventorylist does not exist
Inventory *inv = m_invmgr->getInventory(m_inventoryloc);
if (!inv)
return -1;
InventoryList *ilist = inv->getList(m_listname);
if (!ilist)
return -1;

core::rect<s32> imgrect(0, 0, m_slot_size.X, m_slot_size.Y);
v2s32 base_pos = AbsoluteRect.UpperLeftCorner;

Expand All @@ -210,7 +229,8 @@ s32 GUIInventoryList::getItemIndexAtPos(v2s32 p) const

rect.clipAgainst(AbsoluteClippingRect);

if (rect.getArea() > 0 && rect.isPointInside(p))
if (rect.getArea() > 0 && rect.isPointInside(p) &&
i + m_start_item_i < (s32)ilist->getSize())
return i + m_start_item_i;

return -1;
Expand Down
5 changes: 4 additions & 1 deletion src/gui/guiInventoryList.h
Expand Up @@ -107,7 +107,7 @@ class GUIInventoryList : public gui::IGUIElement
const InventoryLocation m_inventoryloc;
const std::string m_listname;

// specifies the width and height of the inventorylist in itemslots
// the specified width and height of the shown inventorylist in itemslots
const v2s32 m_geom;
// the first item's index in inventory
const s32 m_start_item_i;
Expand All @@ -127,4 +127,7 @@ class GUIInventoryList : public gui::IGUIElement

// the index of the hovered item; -1 if no item is hovered
s32 m_hovered_i;

// we do not want to write a warning on every draw
bool m_already_warned;
};

0 comments on commit 4fb6b6a

Please sign in to comment.