Formspec: allow lists to change size and existence while the formspec is open (#9700)
authorDS <vorunbekannt75@web.de>
Sat, 18 Apr 2020 15:21:10 +0000 (17:21 +0200)
committerGitHub <noreply@github.com>
Sat, 18 Apr 2020 15:21:10 +0000 (17:21 +0200)
Fixes #9640.

src/gui/guiFormSpecMenu.cpp
src/gui/guiInventoryList.cpp
src/gui/guiInventoryList.h

index b0255cf1baead5ee45f677c25a5cc60175f832b2..85ab2eb509e531aeef6c6e0f5d87759ef088890f 100644 (file)
@@ -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;
 
index 53647122963eb5952048734598304548b391f5d1..dfdb60448c7523102bdd868fee8639e64a00715b 100644 (file)
@@ -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)
 {
 }
 
@@ -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();
@@ -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,
@@ -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;
 
@@ -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;
index fd2c3601bd3764a8a293a508faf79256bf2b0199..28e95fbbf4ae02ec4761c92565d6b3914dfca493 100644 (file)
@@ -107,7 +107,7 @@ private:
        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;
@@ -127,4 +127,7 @@ private:
 
        // 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;
 };