Skip to content

Commit 4fb6b6a

Browse files
authoredApr 18, 2020
Formspec: allow lists to change size and existence while the formspec is open (#9700)
Fixes #9640.
1 parent 241bf44 commit 4fb6b6a

File tree

3 files changed

+36
-41
lines changed

3 files changed

+36
-41
lines changed
 

‎src/gui/guiFormSpecMenu.cpp

+1-29
Original file line numberDiff line numberDiff line change
@@ -489,38 +489,10 @@ void GUIFormSpecMenu::parseList(parserData *data, const std::string &element)
489489
start_i = stoi(startindex);
490490

491491
if (geom.X < 0 || geom.Y < 0 || start_i < 0) {
492-
errorstream<< "Invalid list element: '" << element << "'" << std::endl;
492+
errorstream << "Invalid list element: '" << element << "'" << std::endl;
493493
return;
494494
}
495495

496-
// check for the existence of inventory and list
497-
Inventory *inv = m_invmgr->getInventory(loc);
498-
if (!inv) {
499-
warningstream << "GUIFormSpecMenu::parseList(): "
500-
<< "The inventory location "
501-
<< "\"" << loc.dump() << "\" doesn't exist"
502-
<< std::endl;
503-
return;
504-
}
505-
InventoryList *ilist = inv->getList(listname);
506-
if (!ilist) {
507-
warningstream << "GUIFormSpecMenu::parseList(): "
508-
<< "The inventory list \"" << listname << "\" "
509-
<< "@ \"" << loc.dump() << "\" doesn't exist"
510-
<< std::endl;
511-
return;
512-
}
513-
514-
// trim geom if it is larger than the actual inventory size
515-
s32 list_size = (s32)ilist->getSize();
516-
if (list_size < geom.X * geom.Y + start_i) {
517-
list_size -= MYMAX(start_i, 0);
518-
geom.Y = list_size / geom.X;
519-
geom.Y += list_size % geom.X > 0 ? 1 : 0;
520-
if (geom.Y <= 1)
521-
geom.X = list_size;
522-
}
523-
524496
if (!data->explicit_size)
525497
warningstream << "invalid use of list without a size[] element" << std::endl;
526498

‎src/gui/guiInventoryList.cpp

+31-11
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ GUIInventoryList::GUIInventoryList(gui::IGUIEnvironment *env,
4747
m_fs_menu(fs_menu),
4848
m_options(options),
4949
m_font(font),
50-
m_hovered_i(-1)
50+
m_hovered_i(-1),
51+
m_already_warned(false)
5152
{
5253
}
5354

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

5960
Inventory *inv = m_invmgr->getInventory(m_inventoryloc);
6061
if (!inv) {
61-
warningstream << "GUIInventoryList::draw(): "
62-
<< "The inventory location "
63-
<< "\"" << m_inventoryloc.dump() << "\" doesn't exist anymore"
64-
<< std::endl;
62+
if (!m_already_warned) {
63+
warningstream << "GUIInventoryList::draw(): "
64+
<< "The inventory location "
65+
<< "\"" << m_inventoryloc.dump() << "\" doesn't exist"
66+
<< std::endl;
67+
m_already_warned = true;
68+
}
6569
return;
6670
}
6771
InventoryList *ilist = inv->getList(m_listname);
6872
if (!ilist) {
69-
warningstream << "GUIInventoryList::draw(): "
70-
<< "The inventory list \"" << m_listname << "\" @ \""
71-
<< m_inventoryloc.dump() << "\" doesn't exist anymore"
72-
<< std::endl;
73+
if (!m_already_warned) {
74+
warningstream << "GUIInventoryList::draw(): "
75+
<< "The inventory list \"" << m_listname << "\" @ \""
76+
<< m_inventoryloc.dump() << "\" doesn't exist"
77+
<< std::endl;
78+
m_already_warned = true;
79+
}
7380
return;
7481
}
82+
m_already_warned = false;
7583

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

91+
const s32 list_size = (s32)ilist->getSize();
92+
8393
for (s32 i = 0; i < m_geom.X * m_geom.Y; i++) {
8494
s32 item_i = i + m_start_item_i;
85-
if (item_i >= (s32)ilist->getSize())
95+
if (item_i >= list_size)
8696
break;
8797

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

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

210+
// there can not be an item if the inventory or the inventorylist does not exist
211+
Inventory *inv = m_invmgr->getInventory(m_inventoryloc);
212+
if (!inv)
213+
return -1;
214+
InventoryList *ilist = inv->getList(m_listname);
215+
if (!ilist)
216+
return -1;
217+
199218
core::rect<s32> imgrect(0, 0, m_slot_size.X, m_slot_size.Y);
200219
v2s32 base_pos = AbsoluteRect.UpperLeftCorner;
201220

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

211230
rect.clipAgainst(AbsoluteClippingRect);
212231

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

216236
return -1;

‎src/gui/guiInventoryList.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class GUIInventoryList : public gui::IGUIElement
107107
const InventoryLocation m_inventoryloc;
108108
const std::string m_listname;
109109

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

128128
// the index of the hovered item; -1 if no item is hovered
129129
s32 m_hovered_i;
130+
131+
// we do not want to write a warning on every draw
132+
bool m_already_warned;
130133
};

0 commit comments

Comments
 (0)
Please sign in to comment.