diff options
Diffstat (limited to 'src/gui/guiInventoryList.cpp')
-rw-r--r-- | src/gui/guiInventoryList.cpp | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/src/gui/guiInventoryList.cpp b/src/gui/guiInventoryList.cpp new file mode 100644 index 000000000..536471229 --- /dev/null +++ b/src/gui/guiInventoryList.cpp @@ -0,0 +1,217 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "guiInventoryList.h" +#include "guiFormSpecMenu.h" +#include "client/hud.h" +#include "client/client.h" + +GUIInventoryList::GUIInventoryList(gui::IGUIEnvironment *env, + gui::IGUIElement *parent, + s32 id, + const core::rect<s32> &rectangle, + InventoryManager *invmgr, + const InventoryLocation &inventoryloc, + const std::string &listname, + const v2s32 &geom, + const s32 start_item_i, + const v2s32 &slot_size, + const v2f32 &slot_spacing, + GUIFormSpecMenu *fs_menu, + const Options &options, + gui::IGUIFont *font) : + gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle), + m_invmgr(invmgr), + m_inventoryloc(inventoryloc), + m_listname(listname), + m_geom(geom), + m_start_item_i(start_item_i), + m_slot_size(slot_size), + m_slot_spacing(slot_spacing), + m_fs_menu(fs_menu), + m_options(options), + m_font(font), + m_hovered_i(-1) +{ +} + +void GUIInventoryList::draw() +{ + if (!IsVisible) + return; + + Inventory *inv = m_invmgr->getInventory(m_inventoryloc); + if (!inv) { + warningstream << "GUIInventoryList::draw(): " + << "The inventory location " + << "\"" << m_inventoryloc.dump() << "\" doesn't exist anymore" + << std::endl; + 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; + return; + } + + video::IVideoDriver *driver = Environment->getVideoDriver(); + Client *client = m_fs_menu->getClient(); + const ItemSpec *selected_item = m_fs_menu->getSelectedItem(); + + core::rect<s32> imgrect(0, 0, m_slot_size.X, m_slot_size.Y); + v2s32 base_pos = AbsoluteRect.UpperLeftCorner; + + 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()) + break; + + v2s32 p((i % m_geom.X) * m_slot_spacing.X, + (i / m_geom.X) * m_slot_spacing.Y); + core::rect<s32> rect = imgrect + base_pos + p; + ItemStack item = ilist->getItem(item_i); + + bool selected = selected_item + && m_invmgr->getInventory(selected_item->inventoryloc) == inv + && selected_item->listname == m_listname + && selected_item->i == item_i; + core::rect<s32> clipped_rect(rect); + clipped_rect.clipAgainst(AbsoluteClippingRect); + bool hovering = m_hovered_i == item_i; + ItemRotationKind rotation_kind = selected ? IT_ROT_SELECTED : + (hovering ? IT_ROT_HOVERED : IT_ROT_NONE); + + // layer 0 + if (hovering) { + driver->draw2DRectangle(m_options.slotbg_h, rect, &AbsoluteClippingRect); + } else { + driver->draw2DRectangle(m_options.slotbg_n, rect, &AbsoluteClippingRect); + } + + // Draw inv slot borders + if (m_options.slotborder) { + s32 x1 = rect.UpperLeftCorner.X; + s32 y1 = rect.UpperLeftCorner.Y; + s32 x2 = rect.LowerRightCorner.X; + s32 y2 = rect.LowerRightCorner.Y; + s32 border = 1; + core::rect<s32> clipping_rect = Parent ? Parent->getAbsoluteClippingRect() + : core::rect<s32>(); + core::rect<s32> *clipping_rect_ptr = Parent ? &clipping_rect : nullptr; + driver->draw2DRectangle(m_options.slotbordercolor, + core::rect<s32>(v2s32(x1 - border, y1 - border), + v2s32(x2 + border, y1)), clipping_rect_ptr); + driver->draw2DRectangle(m_options.slotbordercolor, + core::rect<s32>(v2s32(x1 - border, y2), + v2s32(x2 + border, y2 + border)), clipping_rect_ptr); + driver->draw2DRectangle(m_options.slotbordercolor, + core::rect<s32>(v2s32(x1 - border, y1), + v2s32(x1, y2)), clipping_rect_ptr); + driver->draw2DRectangle(m_options.slotbordercolor, + core::rect<s32>(v2s32(x2, y1), + v2s32(x2 + border, y2)), clipping_rect_ptr); + } + + // layer 1 + if (selected) + item.takeItem(m_fs_menu->getSelectedAmount()); + + if (!item.empty()) { + // Draw item stack + drawItemStack(driver, m_font, item, rect, &AbsoluteClippingRect, + client, rotation_kind); + // Add hovering tooltip + if (hovering && !selected_item) { + std::string tooltip = item.getDescription(client->idef()); + if (m_fs_menu->doTooltipAppendItemname()) + tooltip += "\n[" + item.name + "]"; + m_fs_menu->addHoveredItemTooltip(tooltip); + } + } + } + + IGUIElement::draw(); +} + +bool GUIInventoryList::OnEvent(const SEvent &event) +{ + if (event.EventType != EET_MOUSE_INPUT_EVENT) { + if (event.EventType == EET_GUI_EVENT && + event.GUIEvent.EventType == EGET_ELEMENT_LEFT) { + // element is no longer hovered + m_hovered_i = -1; + } + return IGUIElement::OnEvent(event); + } + + m_hovered_i = getItemIndexAtPos(v2s32(event.MouseInput.X, event.MouseInput.Y)); + + if (m_hovered_i != -1) + return IGUIElement::OnEvent(event); + + // no item slot at pos of mouse event => allow clicking through + // find the element that would be hovered if this inventorylist was invisible + bool was_visible = IsVisible; + IsVisible = false; + IGUIElement *hovered = + Environment->getRootGUIElement()->getElementFromPoint( + core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y)); + + // if the player clicks outside of the formspec window, hovered is not + // m_fs_menu, but some other weird element (with ID -1). we do however need + // hovered to be m_fs_menu as item dropping when clicking outside of the + // formspec window is handled in its OnEvent callback + if (!hovered || hovered->getID() == -1) + hovered = m_fs_menu; + + bool ret = hovered->OnEvent(event); + + IsVisible = was_visible; + + return ret; +} + +s32 GUIInventoryList::getItemIndexAtPos(v2s32 p) const +{ + if (!IsVisible || AbsoluteClippingRect.getArea() <= 0 || + !AbsoluteClippingRect.isPointInside(p)) + return -1; + + core::rect<s32> imgrect(0, 0, m_slot_size.X, m_slot_size.Y); + v2s32 base_pos = AbsoluteRect.UpperLeftCorner; + + // instead of looping through each slot, we look where p would be in the grid + s32 i = (p.X - base_pos.X) / (s32)m_slot_spacing.X + + m_geom.X * ((p.Y - base_pos.Y) / (s32)m_slot_spacing.Y); + + v2s32 p0((i % m_geom.X) * m_slot_spacing.X, + (i / m_geom.X) * m_slot_spacing.Y); + + core::rect<s32> rect = imgrect + base_pos + p0; + + rect.clipAgainst(AbsoluteClippingRect); + + if (rect.getArea() > 0 && rect.isPointInside(p)) + return i + m_start_item_i; + + return -1; +} |