3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "guiInventoryList.h"
21 #include "guiFormSpecMenu.h"
22 #include "client/hud.h"
23 #include "client/client.h"
25 GUIInventoryList::GUIInventoryList(gui::IGUIEnvironment *env,
26 gui::IGUIElement *parent,
28 const core::rect<s32> &rectangle,
29 InventoryManager *invmgr,
30 const InventoryLocation &inventoryloc,
31 const std::string &listname,
33 const s32 start_item_i,
34 const v2s32 &slot_size,
35 const v2f32 &slot_spacing,
36 GUIFormSpecMenu *fs_menu,
37 const Options &options,
38 gui::IGUIFont *font) :
39 gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle),
41 m_inventoryloc(inventoryloc),
44 m_start_item_i(start_item_i),
45 m_slot_size(slot_size),
46 m_slot_spacing(slot_spacing),
51 m_already_warned(false)
55 void GUIInventoryList::draw()
60 Inventory *inv = m_invmgr->getInventory(m_inventoryloc);
62 if (!m_already_warned) {
63 warningstream << "GUIInventoryList::draw(): "
64 << "The inventory location "
65 << "\"" << m_inventoryloc.dump() << "\" doesn't exist"
67 m_already_warned = true;
71 InventoryList *ilist = inv->getList(m_listname);
73 if (!m_already_warned) {
74 warningstream << "GUIInventoryList::draw(): "
75 << "The inventory list \"" << m_listname << "\" @ \""
76 << m_inventoryloc.dump() << "\" doesn't exist"
78 m_already_warned = true;
82 m_already_warned = false;
84 video::IVideoDriver *driver = Environment->getVideoDriver();
85 Client *client = m_fs_menu->getClient();
86 const ItemSpec *selected_item = m_fs_menu->getSelectedItem();
88 core::rect<s32> imgrect(0, 0, m_slot_size.X, m_slot_size.Y);
89 v2s32 base_pos = AbsoluteRect.UpperLeftCorner;
91 const s32 list_size = (s32)ilist->getSize();
93 for (s32 i = 0; i < m_geom.X * m_geom.Y; i++) {
94 s32 item_i = i + m_start_item_i;
95 if (item_i >= list_size)
98 v2s32 p((i % m_geom.X) * m_slot_spacing.X,
99 (i / m_geom.X) * m_slot_spacing.Y);
100 core::rect<s32> rect = imgrect + base_pos + p;
101 ItemStack item = ilist->getItem(item_i);
103 bool selected = selected_item
104 && m_invmgr->getInventory(selected_item->inventoryloc) == inv
105 && selected_item->listname == m_listname
106 && selected_item->i == item_i;
107 bool hovering = m_hovered_i == item_i;
108 ItemRotationKind rotation_kind = selected ? IT_ROT_SELECTED :
109 (hovering ? IT_ROT_HOVERED : IT_ROT_NONE);
113 driver->draw2DRectangle(m_options.slotbg_h, rect, &AbsoluteClippingRect);
115 driver->draw2DRectangle(m_options.slotbg_n, rect, &AbsoluteClippingRect);
118 // Draw inv slot borders
119 if (m_options.slotborder) {
120 s32 x1 = rect.UpperLeftCorner.X;
121 s32 y1 = rect.UpperLeftCorner.Y;
122 s32 x2 = rect.LowerRightCorner.X;
123 s32 y2 = rect.LowerRightCorner.Y;
125 core::rect<s32> clipping_rect = Parent ? Parent->getAbsoluteClippingRect()
127 core::rect<s32> *clipping_rect_ptr = Parent ? &clipping_rect : nullptr;
128 driver->draw2DRectangle(m_options.slotbordercolor,
129 core::rect<s32>(v2s32(x1 - border, y1 - border),
130 v2s32(x2 + border, y1)), clipping_rect_ptr);
131 driver->draw2DRectangle(m_options.slotbordercolor,
132 core::rect<s32>(v2s32(x1 - border, y2),
133 v2s32(x2 + border, y2 + border)), clipping_rect_ptr);
134 driver->draw2DRectangle(m_options.slotbordercolor,
135 core::rect<s32>(v2s32(x1 - border, y1),
136 v2s32(x1, y2)), clipping_rect_ptr);
137 driver->draw2DRectangle(m_options.slotbordercolor,
138 core::rect<s32>(v2s32(x2, y1),
139 v2s32(x2 + border, y2)), clipping_rect_ptr);
144 item.takeItem(m_fs_menu->getSelectedAmount());
148 drawItemStack(driver, m_font, item, rect, &AbsoluteClippingRect,
149 client, rotation_kind);
150 // Add hovering tooltip
151 if (hovering && !selected_item) {
152 std::string tooltip = item.getDescription(client->idef());
153 if (m_fs_menu->doTooltipAppendItemname())
154 tooltip += "\n[" + item.name + "]";
155 m_fs_menu->addHoveredItemTooltip(tooltip);
163 bool GUIInventoryList::OnEvent(const SEvent &event)
165 if (event.EventType != EET_MOUSE_INPUT_EVENT) {
166 if (event.EventType == EET_GUI_EVENT &&
167 event.GUIEvent.EventType == EGET_ELEMENT_LEFT) {
168 // element is no longer hovered
171 return IGUIElement::OnEvent(event);
174 m_hovered_i = getItemIndexAtPos(v2s32(event.MouseInput.X, event.MouseInput.Y));
176 if (m_hovered_i != -1)
177 return IGUIElement::OnEvent(event);
179 // no item slot at pos of mouse event => allow clicking through
180 // find the element that would be hovered if this inventorylist was invisible
181 bool was_visible = IsVisible;
183 IGUIElement *hovered =
184 Environment->getRootGUIElement()->getElementFromPoint(
185 core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y));
187 // if the player clicks outside of the formspec window, hovered is not
188 // m_fs_menu, but some other weird element (with ID -1). we do however need
189 // hovered to be m_fs_menu as item dropping when clicking outside of the
190 // formspec window is handled in its OnEvent callback
191 if (!hovered || hovered->getID() == -1)
194 bool ret = hovered->OnEvent(event);
196 IsVisible = was_visible;
201 s32 GUIInventoryList::getItemIndexAtPos(v2s32 p) const
203 // no item if no gui element at pointer
204 if (!IsVisible || AbsoluteClippingRect.getArea() <= 0 ||
205 !AbsoluteClippingRect.isPointInside(p))
208 // there can not be an item if the inventory or the inventorylist does not exist
209 Inventory *inv = m_invmgr->getInventory(m_inventoryloc);
212 InventoryList *ilist = inv->getList(m_listname);
216 core::rect<s32> imgrect(0, 0, m_slot_size.X, m_slot_size.Y);
217 v2s32 base_pos = AbsoluteRect.UpperLeftCorner;
219 // instead of looping through each slot, we look where p would be in the grid
220 s32 i = (p.X - base_pos.X) / (s32)m_slot_spacing.X
221 + m_geom.X * ((p.Y - base_pos.Y) / (s32)m_slot_spacing.Y);
223 v2s32 p0((i % m_geom.X) * m_slot_spacing.X,
224 (i / m_geom.X) * m_slot_spacing.Y);
226 core::rect<s32> rect = imgrect + base_pos + p0;
228 rect.clipAgainst(AbsoluteClippingRect);
230 if (rect.getArea() > 0 && rect.isPointInside(p) &&
231 i + m_start_item_i < (s32)ilist->getSize())
232 return i + m_start_item_i;