mirror of
https://github.com/minetest/minetest.git
synced 2024-11-27 01:53:45 +01:00
Formspec: Create a new class for inventorylists (#9287)
This commit is contained in:
parent
908e762479
commit
1116918dbb
@ -189,6 +189,7 @@ LOCAL_SRC_FILES := \
|
|||||||
jni/src/gui/guiEngine.cpp \
|
jni/src/gui/guiEngine.cpp \
|
||||||
jni/src/gui/guiFormSpecMenu.cpp \
|
jni/src/gui/guiFormSpecMenu.cpp \
|
||||||
jni/src/gui/guiHyperText.cpp \
|
jni/src/gui/guiHyperText.cpp \
|
||||||
|
jni/src/gui/guiInventoryList.cpp \
|
||||||
jni/src/gui/guiItemImage.cpp \
|
jni/src/gui/guiItemImage.cpp \
|
||||||
jni/src/gui/guiKeyChangeMenu.cpp \
|
jni/src/gui/guiKeyChangeMenu.cpp \
|
||||||
jni/src/gui/guiPasswordChange.cpp \
|
jni/src/gui/guiPasswordChange.cpp \
|
||||||
|
@ -1946,8 +1946,6 @@ For coloured text you can use `minetest.colorize`.
|
|||||||
|
|
||||||
Since formspec version 3, elements drawn in the order they are defined. All
|
Since formspec version 3, elements drawn in the order they are defined. All
|
||||||
background elements are drawn before all other elements.
|
background elements are drawn before all other elements.
|
||||||
`list` elements are an exception here. They are drawn last. This, however, might
|
|
||||||
be changed at any time.
|
|
||||||
|
|
||||||
**WARNING**: do _not_ use a element name starting with `key_`; those names are
|
**WARNING**: do _not_ use a element name starting with `key_`; those names are
|
||||||
reserved to pass key press events to formspec!
|
reserved to pass key press events to formspec!
|
||||||
@ -2058,7 +2056,6 @@ Elements
|
|||||||
be shown if the inventory list is of size 0.
|
be shown if the inventory list is of size 0.
|
||||||
* **Note**: With the new coordinate system, the spacing between inventory
|
* **Note**: With the new coordinate system, the spacing between inventory
|
||||||
slots is one-fourth the size of an inventory slot.
|
slots is one-fourth the size of an inventory slot.
|
||||||
* **Note**: Lists are drawn after every other element. This might change at any time.
|
|
||||||
|
|
||||||
### `list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;<starting item index>]`
|
### `list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;<starting item index>]`
|
||||||
|
|
||||||
@ -2066,7 +2063,6 @@ Elements
|
|||||||
be shown if the inventory list is of size 0.
|
be shown if the inventory list is of size 0.
|
||||||
* **Note**: With the new coordinate system, the spacing between inventory
|
* **Note**: With the new coordinate system, the spacing between inventory
|
||||||
slots is one-fourth the size of an inventory slot.
|
slots is one-fourth the size of an inventory slot.
|
||||||
* **Note**: Lists are drawn after every other element. This might change at any time.
|
|
||||||
|
|
||||||
### `listring[<inventory location>;<list name>]`
|
### `listring[<inventory location>;<list name>]`
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ set(gui_SRCS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiEditBoxWithScrollbar.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiEditBoxWithScrollbar.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiEngine.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiEngine.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiFormSpecMenu.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiFormSpecMenu.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/guiInventoryList.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiItemImage.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiItemImage.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiKeyChangeMenu.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiKeyChangeMenu.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiPasswordChange.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiPasswordChange.cpp
|
||||||
|
@ -61,6 +61,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "guiButtonImage.h"
|
#include "guiButtonImage.h"
|
||||||
#include "guiButtonItemImage.h"
|
#include "guiButtonItemImage.h"
|
||||||
#include "guiEditBoxWithScrollbar.h"
|
#include "guiEditBoxWithScrollbar.h"
|
||||||
|
#include "guiInventoryList.h"
|
||||||
#include "guiItemImage.h"
|
#include "guiItemImage.h"
|
||||||
#include "guiScrollBar.h"
|
#include "guiScrollBar.h"
|
||||||
#include "guiTable.h"
|
#include "guiTable.h"
|
||||||
@ -130,7 +131,7 @@ GUIFormSpecMenu::~GUIFormSpecMenu()
|
|||||||
for (auto &table_it : m_tables)
|
for (auto &table_it : m_tables)
|
||||||
table_it.second->drop();
|
table_it.second->drop();
|
||||||
for (auto &inventorylist_it : m_inventorylists)
|
for (auto &inventorylist_it : m_inventorylists)
|
||||||
inventorylist_it.e->drop();
|
inventorylist_it->drop();
|
||||||
for (auto &checkbox_it : m_checkboxes)
|
for (auto &checkbox_it : m_checkboxes)
|
||||||
checkbox_it.second->drop();
|
checkbox_it.second->drop();
|
||||||
for (auto &scrollbar_it : m_scrollbars)
|
for (auto &scrollbar_it : m_scrollbars)
|
||||||
@ -347,7 +348,7 @@ void GUIFormSpecMenu::parseContainerEnd(parserData* data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIFormSpecMenu::parseList(parserData* data, const std::string &element)
|
void GUIFormSpecMenu::parseList(parserData *data, const std::string &element)
|
||||||
{
|
{
|
||||||
if (m_client == 0) {
|
if (m_client == 0) {
|
||||||
warningstream<<"invalid use of 'list' with m_client==0"<<std::endl;
|
warningstream<<"invalid use of 'list' with m_client==0"<<std::endl;
|
||||||
@ -429,36 +430,28 @@ void GUIFormSpecMenu::parseList(parserData* data, const std::string &element)
|
|||||||
3
|
3
|
||||||
);
|
);
|
||||||
|
|
||||||
v2s32 pos;
|
v2f32 slot_spacing = data->real_coordinates ?
|
||||||
core::rect<s32> rect;
|
v2f32(imgsize.X * 1.25f, imgsize.Y * 1.25f) : spacing;
|
||||||
|
|
||||||
if (data->real_coordinates) {
|
v2s32 pos = data->real_coordinates ? getRealCoordinateBasePos(v_pos)
|
||||||
pos = getRealCoordinateBasePos(v_pos);
|
: getElementBasePos(&v_pos);
|
||||||
rect = core::rect<s32>(pos.X, pos.Y,
|
|
||||||
pos.X + (geom.X - 1) * (imgsize.X * 1.25) + imgsize.X,
|
|
||||||
pos.Y + (geom.Y - 1) * (imgsize.Y * 1.25) + imgsize.Y);
|
|
||||||
} else {
|
|
||||||
pos = getElementBasePos(&v_pos);
|
|
||||||
rect = core::rect<s32>(pos.X, pos.Y,
|
|
||||||
pos.X + (geom.X - 1) * spacing.X + imgsize.X,
|
|
||||||
pos.Y + (geom.Y - 1) * spacing.Y + imgsize.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
gui::IGUIElement *e = new gui::IGUIElement(EGUIET_ELEMENT, Environment,
|
core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y,
|
||||||
this, spec.fid, rect);
|
pos.X + (geom.X - 1) * slot_spacing.X + imgsize.X,
|
||||||
|
pos.Y + (geom.Y - 1) * slot_spacing.Y + imgsize.Y);
|
||||||
|
|
||||||
// the element the list is bound to should not block mouse-clicks
|
GUIInventoryList *e = new GUIInventoryList(Environment, this, spec.fid,
|
||||||
e->setVisible(false);
|
rect, m_invmgr, loc, listname, geom, start_i, imgsize, slot_spacing,
|
||||||
|
this, data->inventorylist_options, m_font);
|
||||||
|
|
||||||
m_inventorylists.emplace_back(loc, listname, e, geom, start_i,
|
m_inventorylists.push_back(e);
|
||||||
data->real_coordinates);
|
|
||||||
m_fields.push_back(spec);
|
m_fields.push_back(spec);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
errorstream<< "Invalid list element(" << parts.size() << "): '" << element << "'" << std::endl;
|
errorstream<< "Invalid list element(" << parts.size() << "): '" << element << "'" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIFormSpecMenu::parseListRing(parserData* data, const std::string &element)
|
void GUIFormSpecMenu::parseListRing(parserData *data, const std::string &element)
|
||||||
{
|
{
|
||||||
if (m_client == 0) {
|
if (m_client == 0) {
|
||||||
errorstream << "WARNING: invalid use of 'listring' with m_client==0" << std::endl;
|
errorstream << "WARNING: invalid use of 'listring' with m_client==0" << std::endl;
|
||||||
@ -485,10 +478,10 @@ void GUIFormSpecMenu::parseListRing(parserData* data, const std::string &element
|
|||||||
if (element.empty() && m_inventorylists.size() > 1) {
|
if (element.empty() && m_inventorylists.size() > 1) {
|
||||||
size_t siz = m_inventorylists.size();
|
size_t siz = m_inventorylists.size();
|
||||||
// insert the last two inv list elements into the list ring
|
// insert the last two inv list elements into the list ring
|
||||||
const ListDrawSpec &spa = m_inventorylists[siz - 2];
|
const GUIInventoryList *spa = m_inventorylists[siz - 2];
|
||||||
const ListDrawSpec &spb = m_inventorylists[siz - 1];
|
const GUIInventoryList *spb = m_inventorylists[siz - 1];
|
||||||
m_inventory_rings.emplace_back(spa.inventoryloc, spa.listname);
|
m_inventory_rings.emplace_back(spa->getInventoryloc(), spa->getListname());
|
||||||
m_inventory_rings.emplace_back(spb.inventoryloc, spb.listname);
|
m_inventory_rings.emplace_back(spb->getInventoryloc(), spb->getListname());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2171,12 +2164,13 @@ void GUIFormSpecMenu::parseListColors(parserData* data, const std::string &eleme
|
|||||||
if (((parts.size() == 2) || (parts.size() == 3) || (parts.size() == 5)) ||
|
if (((parts.size() == 2) || (parts.size() == 3) || (parts.size() == 5)) ||
|
||||||
((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION)))
|
((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION)))
|
||||||
{
|
{
|
||||||
parseColorString(parts[0], m_slotbg_n, false);
|
parseColorString(parts[0], data->inventorylist_options.slotbg_n, false);
|
||||||
parseColorString(parts[1], m_slotbg_h, false);
|
parseColorString(parts[1], data->inventorylist_options.slotbg_h, false);
|
||||||
|
|
||||||
if (parts.size() >= 3) {
|
if (parts.size() >= 3) {
|
||||||
if (parseColorString(parts[2], m_slotbordercolor, false)) {
|
if (parseColorString(parts[2], data->inventorylist_options.slotbordercolor,
|
||||||
m_slotborder = true;
|
false)) {
|
||||||
|
data->inventorylist_options.slotborder = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (parts.size() == 5) {
|
if (parts.size() == 5) {
|
||||||
@ -2187,6 +2181,14 @@ void GUIFormSpecMenu::parseListColors(parserData* data, const std::string &eleme
|
|||||||
if (parseColorString(parts[4], tmp_color, false))
|
if (parseColorString(parts[4], tmp_color, false))
|
||||||
m_default_tooltip_color = tmp_color;
|
m_default_tooltip_color = tmp_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update all already parsed inventorylists
|
||||||
|
for (GUIInventoryList *e : m_inventorylists) {
|
||||||
|
e->setSlotBGColors(data->inventorylist_options.slotbg_n,
|
||||||
|
data->inventorylist_options.slotbg_h);
|
||||||
|
e->setSlotBorders(data->inventorylist_options.slotborder,
|
||||||
|
data->inventorylist_options.slotbordercolor);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
errorstream<< "Invalid listcolors element(" << parts.size() << "): '" << element << "'" << std::endl;
|
errorstream<< "Invalid listcolors element(" << parts.size() << "): '" << element << "'" << std::endl;
|
||||||
@ -2673,7 +2675,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
|||||||
for (auto &table_it : m_tables)
|
for (auto &table_it : m_tables)
|
||||||
table_it.second->drop();
|
table_it.second->drop();
|
||||||
for (auto &inventorylist_it : m_inventorylists)
|
for (auto &inventorylist_it : m_inventorylists)
|
||||||
inventorylist_it.e->drop();
|
inventorylist_it->drop();
|
||||||
for (auto &checkbox_it : m_checkboxes)
|
for (auto &checkbox_it : m_checkboxes)
|
||||||
checkbox_it.second->drop();
|
checkbox_it.second->drop();
|
||||||
for (auto &scrollbar_it : m_scrollbars)
|
for (auto &scrollbar_it : m_scrollbars)
|
||||||
@ -2692,8 +2694,6 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
|||||||
// Base position of contents of form
|
// Base position of contents of form
|
||||||
mydata.basepos = getBasePos();
|
mydata.basepos = getBasePos();
|
||||||
|
|
||||||
/* Convert m_init_draw_spec to m_inventorylists */
|
|
||||||
|
|
||||||
m_inventorylists.clear();
|
m_inventorylists.clear();
|
||||||
m_backgrounds.clear();
|
m_backgrounds.clear();
|
||||||
m_tables.clear();
|
m_tables.clear();
|
||||||
@ -2732,15 +2732,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_slotbg_n = video::SColor(255,128,128,128);
|
|
||||||
m_slotbg_h = video::SColor(255,192,192,192);
|
|
||||||
|
|
||||||
m_default_tooltip_bgcolor = video::SColor(255,110,130,60);
|
m_default_tooltip_bgcolor = video::SColor(255,110,130,60);
|
||||||
m_default_tooltip_color = video::SColor(255,255,255,255);
|
m_default_tooltip_color = video::SColor(255,255,255,255);
|
||||||
|
|
||||||
m_slotbordercolor = video::SColor(200,0,0,0);
|
|
||||||
m_slotborder = false;
|
|
||||||
|
|
||||||
// Add tooltip
|
// Add tooltip
|
||||||
{
|
{
|
||||||
assert(!m_tooltip_element);
|
assert(!m_tooltip_element);
|
||||||
@ -3073,7 +3067,7 @@ bool GUIFormSpecMenu::getAndroidUIInput()
|
|||||||
std::string fieldname = m_jni_field_name;
|
std::string fieldname = m_jni_field_name;
|
||||||
m_jni_field_name.clear();
|
m_jni_field_name.clear();
|
||||||
|
|
||||||
for(std::vector<FieldSpec>::iterator iter = m_fields.begin();
|
for (std::vector<FieldSpec>::iterator iter = m_fields.begin();
|
||||||
iter != m_fields.end(); ++iter) {
|
iter != m_fields.end(); ++iter) {
|
||||||
|
|
||||||
if (iter->fname != fieldname) {
|
if (iter->fname != fieldname) {
|
||||||
@ -3097,140 +3091,18 @@ bool GUIFormSpecMenu::getAndroidUIInput()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GUIFormSpecMenu::ItemSpec GUIFormSpecMenu::getItemAtPos(v2s32 p) const
|
GUIInventoryList::ItemSpec GUIFormSpecMenu::getItemAtPos(v2s32 p) const
|
||||||
{
|
{
|
||||||
core::rect<s32> imgrect(0, 0, imgsize.X, imgsize.Y);
|
core::rect<s32> imgrect(0, 0, imgsize.X, imgsize.Y);
|
||||||
|
|
||||||
for (const GUIFormSpecMenu::ListDrawSpec &s : m_inventorylists) {
|
for (const GUIInventoryList *e : m_inventorylists) {
|
||||||
core::rect<s32> clipping_rect = s.e->getAbsoluteClippingRect();
|
s32 item_index = e->getItemIndexAtPos(p);
|
||||||
v2s32 base_pos = s.e->getAbsolutePosition().UpperLeftCorner;
|
if (item_index != -1)
|
||||||
for(s32 i=0; i<s.geom.X*s.geom.Y; i++) {
|
return GUIInventoryList::ItemSpec(e->getInventoryloc(), e->getListname(),
|
||||||
s32 item_i = i + s.start_item_i;
|
item_index);
|
||||||
|
|
||||||
s32 x;
|
|
||||||
s32 y;
|
|
||||||
if (s.real_coordinates) {
|
|
||||||
x = (i%s.geom.X) * (imgsize.X * 1.25);
|
|
||||||
y = (i/s.geom.X) * (imgsize.Y * 1.25);
|
|
||||||
} else {
|
|
||||||
x = (i%s.geom.X) * spacing.X;
|
|
||||||
y = (i/s.geom.X) * spacing.Y;
|
|
||||||
}
|
|
||||||
v2s32 p0(x,y);
|
|
||||||
core::rect<s32> rect = imgrect + base_pos + p0;
|
|
||||||
rect.clipAgainst(clipping_rect);
|
|
||||||
if (rect.getArea() > 0 && rect.isPointInside(p))
|
|
||||||
return ItemSpec(s.inventoryloc, s.listname, item_i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ItemSpec(InventoryLocation(), "", -1);
|
return GUIInventoryList::ItemSpec(InventoryLocation(), "", -1);
|
||||||
}
|
|
||||||
|
|
||||||
void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int layer,
|
|
||||||
bool &item_hovered)
|
|
||||||
{
|
|
||||||
video::IVideoDriver* driver = Environment->getVideoDriver();
|
|
||||||
|
|
||||||
Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
|
|
||||||
if (!inv) {
|
|
||||||
warningstream<<"GUIFormSpecMenu::drawList(): "
|
|
||||||
<< "The inventory location "
|
|
||||||
<< "\"" << s.inventoryloc.dump() << "\" doesn't exist anymore"
|
|
||||||
<< std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
InventoryList *ilist = inv->getList(s.listname);
|
|
||||||
if (!ilist) {
|
|
||||||
warningstream << "GUIFormSpecMenu::drawList(): "
|
|
||||||
<< "The inventory list \"" << s.listname << "\" @ \""
|
|
||||||
<< s.inventoryloc.dump() << "\" doesn't exist anymore"
|
|
||||||
<< std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
core::rect<s32> imgrect(0, 0, imgsize.X, imgsize.Y);
|
|
||||||
core::rect<s32> clipping_rect = s.e->getAbsoluteClippingRect();
|
|
||||||
v2s32 base_pos = s.e->getAbsolutePosition().UpperLeftCorner;
|
|
||||||
|
|
||||||
for (s32 i = 0; i < s.geom.X * s.geom.Y; i++) {
|
|
||||||
s32 item_i = i + s.start_item_i;
|
|
||||||
if (item_i >= (s32)ilist->getSize())
|
|
||||||
break;
|
|
||||||
|
|
||||||
s32 x;
|
|
||||||
s32 y;
|
|
||||||
if (s.real_coordinates) {
|
|
||||||
x = (i%s.geom.X) * (imgsize.X * 1.25);
|
|
||||||
y = (i/s.geom.X) * (imgsize.Y * 1.25);
|
|
||||||
} else {
|
|
||||||
x = (i%s.geom.X) * spacing.X;
|
|
||||||
y = (i/s.geom.X) * spacing.Y;
|
|
||||||
}
|
|
||||||
v2s32 p(x,y);
|
|
||||||
core::rect<s32> rect = imgrect + base_pos + p;
|
|
||||||
ItemStack item = ilist->getItem(item_i);
|
|
||||||
|
|
||||||
bool selected = m_selected_item
|
|
||||||
&& m_invmgr->getInventory(m_selected_item->inventoryloc) == inv
|
|
||||||
&& m_selected_item->listname == s.listname
|
|
||||||
&& m_selected_item->i == item_i;
|
|
||||||
core::rect<s32> clipped_rect(rect);
|
|
||||||
clipped_rect.clipAgainst(clipping_rect);
|
|
||||||
bool hovering = clipped_rect.getArea() > 0 &&
|
|
||||||
clipped_rect.isPointInside(m_pointer);
|
|
||||||
ItemRotationKind rotation_kind = selected ? IT_ROT_SELECTED :
|
|
||||||
(hovering ? IT_ROT_HOVERED : IT_ROT_NONE);
|
|
||||||
|
|
||||||
if (layer == 0) {
|
|
||||||
if (hovering) {
|
|
||||||
item_hovered = true;
|
|
||||||
driver->draw2DRectangle(m_slotbg_h, rect, &clipping_rect);
|
|
||||||
} else {
|
|
||||||
driver->draw2DRectangle(m_slotbg_n, rect, &clipping_rect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Draw inv slot borders
|
|
||||||
if (m_slotborder) {
|
|
||||||
s32 x1 = rect.UpperLeftCorner.X;
|
|
||||||
s32 y1 = rect.UpperLeftCorner.Y;
|
|
||||||
s32 x2 = rect.LowerRightCorner.X;
|
|
||||||
s32 y2 = rect.LowerRightCorner.Y;
|
|
||||||
s32 border = 1;
|
|
||||||
driver->draw2DRectangle(m_slotbordercolor,
|
|
||||||
core::rect<s32>(v2s32(x1 - border, y1 - border),
|
|
||||||
v2s32(x2 + border, y1)), &clipping_rect);
|
|
||||||
driver->draw2DRectangle(m_slotbordercolor,
|
|
||||||
core::rect<s32>(v2s32(x1 - border, y2),
|
|
||||||
v2s32(x2 + border, y2 + border)), &clipping_rect);
|
|
||||||
driver->draw2DRectangle(m_slotbordercolor,
|
|
||||||
core::rect<s32>(v2s32(x1 - border, y1),
|
|
||||||
v2s32(x1, y2)), &clipping_rect);
|
|
||||||
driver->draw2DRectangle(m_slotbordercolor,
|
|
||||||
core::rect<s32>(v2s32(x2, y1),
|
|
||||||
v2s32(x2 + border, y2)), &clipping_rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (layer == 1) {
|
|
||||||
if (selected)
|
|
||||||
item.takeItem(m_selected_amount);
|
|
||||||
|
|
||||||
if (!item.empty()) {
|
|
||||||
// Draw item stack
|
|
||||||
drawItemStack(driver, m_font, item,
|
|
||||||
rect, &clipping_rect, m_client, rotation_kind);
|
|
||||||
// Draw tooltip
|
|
||||||
if (hovering && !m_selected_item) {
|
|
||||||
std::string tooltip = item.getDescription(m_client->idef());
|
|
||||||
if (m_tooltip_append_itemname)
|
|
||||||
tooltip += "\n[" + item.name + "]";
|
|
||||||
showTooltip(utf8_to_wide(tooltip), m_default_tooltip_color,
|
|
||||||
m_default_tooltip_bgcolor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIFormSpecMenu::drawSelectedItem()
|
void GUIFormSpecMenu::drawSelectedItem()
|
||||||
@ -3273,6 +3145,8 @@ void GUIFormSpecMenu::drawMenu()
|
|||||||
gui::IGUIFont *old_font = skin->getFont();
|
gui::IGUIFont *old_font = skin->getFont();
|
||||||
skin->setFont(m_font);
|
skin->setFont(m_font);
|
||||||
|
|
||||||
|
m_hovered_item_tooltips.clear();
|
||||||
|
|
||||||
updateSelectedItem();
|
updateSelectedItem();
|
||||||
|
|
||||||
video::IVideoDriver* driver = Environment->getVideoDriver();
|
video::IVideoDriver* driver = Environment->getVideoDriver();
|
||||||
@ -3315,21 +3189,17 @@ void GUIFormSpecMenu::drawMenu()
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Call base class
|
Call base class
|
||||||
|
(This is where all the drawing happens.)
|
||||||
*/
|
*/
|
||||||
gui::IGUIElement::draw();
|
gui::IGUIElement::draw();
|
||||||
|
|
||||||
/*
|
// Draw hovered item tooltips
|
||||||
Draw items
|
for (const std::string &tooltip : m_hovered_item_tooltips) {
|
||||||
Layer 0: Item slot rectangles
|
showTooltip(utf8_to_wide(tooltip), m_default_tooltip_color,
|
||||||
Layer 1: Item images; prepare tooltip
|
m_default_tooltip_bgcolor);
|
||||||
*/
|
|
||||||
bool item_hovered = false;
|
|
||||||
for (int layer = 0; layer < 2; layer++) {
|
|
||||||
for (const GUIFormSpecMenu::ListDrawSpec &spec : m_inventorylists) {
|
|
||||||
drawList(spec, layer, item_hovered);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!item_hovered) {
|
|
||||||
|
if (m_hovered_item_tooltips.empty()) {
|
||||||
// reset rotation time
|
// reset rotation time
|
||||||
drawItemStack(driver, m_font, ItemStack(),
|
drawItemStack(driver, m_font, ItemStack(),
|
||||||
core::rect<s32>(v2s32(0, 0), v2s32(0, 0)),
|
core::rect<s32>(v2s32(0, 0), v2s32(0, 0)),
|
||||||
@ -3463,11 +3333,11 @@ void GUIFormSpecMenu::updateSelectedItem()
|
|||||||
|
|
||||||
// If craftresult is nonempty and nothing else is selected, select it now.
|
// If craftresult is nonempty and nothing else is selected, select it now.
|
||||||
if (!m_selected_item) {
|
if (!m_selected_item) {
|
||||||
for (const GUIFormSpecMenu::ListDrawSpec &s : m_inventorylists) {
|
for (const GUIInventoryList *e : m_inventorylists) {
|
||||||
if (s.listname != "craftpreview")
|
if (e->getListname() != "craftpreview")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
|
Inventory *inv = m_invmgr->getInventory(e->getInventoryloc());
|
||||||
if (!inv)
|
if (!inv)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -3481,8 +3351,8 @@ void GUIFormSpecMenu::updateSelectedItem()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Grab selected item from the crafting result list
|
// Grab selected item from the crafting result list
|
||||||
m_selected_item = new ItemSpec;
|
m_selected_item = new GUIInventoryList::ItemSpec;
|
||||||
m_selected_item->inventoryloc = s.inventoryloc;
|
m_selected_item->inventoryloc = e->getInventoryloc();
|
||||||
m_selected_item->listname = "craftresult";
|
m_selected_item->listname = "craftresult";
|
||||||
m_selected_item->i = 0;
|
m_selected_item->i = 0;
|
||||||
m_selected_amount = item.count;
|
m_selected_amount = item.count;
|
||||||
@ -3503,16 +3373,12 @@ ItemStack GUIFormSpecMenu::verifySelectedItem()
|
|||||||
// If the selected stack has become smaller, adjust m_selected_amount.
|
// If the selected stack has become smaller, adjust m_selected_amount.
|
||||||
// Return the selected stack.
|
// Return the selected stack.
|
||||||
|
|
||||||
if(m_selected_item)
|
if (m_selected_item) {
|
||||||
{
|
if (m_selected_item->isValid()) {
|
||||||
if(m_selected_item->isValid())
|
|
||||||
{
|
|
||||||
Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc);
|
Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc);
|
||||||
if(inv)
|
if (inv) {
|
||||||
{
|
|
||||||
InventoryList *list = inv->getList(m_selected_item->listname);
|
InventoryList *list = inv->getList(m_selected_item->listname);
|
||||||
if(list && (u32) m_selected_item->i < list->getSize())
|
if (list && (u32) m_selected_item->i < list->getSize()) {
|
||||||
{
|
|
||||||
ItemStack stack = list->getItem(m_selected_item->i);
|
ItemStack stack = list->getItem(m_selected_item->i);
|
||||||
if (!m_selected_swap.empty()) {
|
if (!m_selected_swap.empty()) {
|
||||||
if (m_selected_swap.name == stack.name &&
|
if (m_selected_swap.name == stack.name &&
|
||||||
@ -3530,7 +3396,7 @@ ItemStack GUIFormSpecMenu::verifySelectedItem()
|
|||||||
|
|
||||||
// selection was not valid
|
// selection was not valid
|
||||||
delete m_selected_item;
|
delete m_selected_item;
|
||||||
m_selected_item = NULL;
|
m_selected_item = nullptr;
|
||||||
m_selected_amount = 0;
|
m_selected_amount = 0;
|
||||||
m_selected_dragging = false;
|
m_selected_dragging = false;
|
||||||
}
|
}
|
||||||
@ -3670,9 +3536,9 @@ void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode=quit_mode_no)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isChild(gui::IGUIElement * tocheck, gui::IGUIElement * parent)
|
static bool isChild(gui::IGUIElement *tocheck, gui::IGUIElement *parent)
|
||||||
{
|
{
|
||||||
while(tocheck != NULL) {
|
while (tocheck) {
|
||||||
if (tocheck == parent) {
|
if (tocheck == parent) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -3709,8 +3575,8 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fix Esc/Return key being eaten by checkboxen and tables
|
// Fix Esc/Return key being eaten by checkboxen and tables
|
||||||
if(event.EventType==EET_KEY_INPUT_EVENT) {
|
if (event.EventType == EET_KEY_INPUT_EVENT) {
|
||||||
KeyPress kp(event.KeyInput);
|
KeyPress kp(event.KeyInput);
|
||||||
if (kp == EscapeKey || kp == CancelKey
|
if (kp == EscapeKey || kp == CancelKey
|
||||||
|| kp == getKeySetting("keymap_inventory")
|
|| kp == getKeySetting("keymap_inventory")
|
||||||
|| event.KeyInput.Key==KEY_RETURN) {
|
|| event.KeyInput.Key==KEY_RETURN) {
|
||||||
@ -3749,7 +3615,7 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event)
|
|||||||
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
|
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
|
||||||
m_old_tooltip_id = -1;
|
m_old_tooltip_id = -1;
|
||||||
}
|
}
|
||||||
if (!isChild(hovered,this)) {
|
if (!isChild(hovered, this)) {
|
||||||
if (DoubleClickDetection(event)) {
|
if (DoubleClickDetection(event)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -3920,7 +3786,7 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
|||||||
|
|
||||||
m_old_tooltip_id = -1;
|
m_old_tooltip_id = -1;
|
||||||
updateSelectedItem();
|
updateSelectedItem();
|
||||||
ItemSpec s = getItemAtPos(m_pointer);
|
GUIInventoryList::ItemSpec s = getItemAtPos(m_pointer);
|
||||||
|
|
||||||
Inventory *inv_selected = NULL;
|
Inventory *inv_selected = NULL;
|
||||||
Inventory *inv_s = NULL;
|
Inventory *inv_s = NULL;
|
||||||
@ -4022,8 +3888,9 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
|||||||
case BET_DOWN:
|
case BET_DOWN:
|
||||||
// Some mouse button has been pressed
|
// Some mouse button has been pressed
|
||||||
|
|
||||||
//infostream<<"Mouse button "<<button<<" pressed at p=("
|
//infostream << "Mouse button " << button << " pressed at p=("
|
||||||
// <<p.X<<","<<p.Y<<")"<<std::endl;
|
// << event.MouseInput.X << "," << event.MouseInput.Y << ")"
|
||||||
|
// << std::endl;
|
||||||
|
|
||||||
m_selected_dragging = false;
|
m_selected_dragging = false;
|
||||||
|
|
||||||
@ -4033,7 +3900,7 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
|||||||
} else if (!m_selected_item) {
|
} else if (!m_selected_item) {
|
||||||
if (s_count && button != BET_WHEEL_UP) {
|
if (s_count && button != BET_WHEEL_UP) {
|
||||||
// Non-empty stack has been clicked: select or shift-move it
|
// Non-empty stack has been clicked: select or shift-move it
|
||||||
m_selected_item = new ItemSpec(s);
|
m_selected_item = new GUIInventoryList::ItemSpec(s);
|
||||||
|
|
||||||
u32 count;
|
u32 count;
|
||||||
if (button == BET_RIGHT)
|
if (button == BET_RIGHT)
|
||||||
@ -4261,7 +4128,7 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
|||||||
|
|
||||||
// if there are no items selected or the selected item
|
// if there are no items selected or the selected item
|
||||||
// belongs to craftresult list, proceed with crafting
|
// belongs to craftresult list, proceed with crafting
|
||||||
if (m_selected_item == NULL ||
|
if (!m_selected_item ||
|
||||||
!m_selected_item->isValid() || m_selected_item->listname == "craftresult") {
|
!m_selected_item->isValid() || m_selected_item->listname == "craftresult") {
|
||||||
|
|
||||||
assert(inv_s);
|
assert(inv_s);
|
||||||
@ -4279,7 +4146,7 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
|||||||
if (m_selected_amount == 0) {
|
if (m_selected_amount == 0) {
|
||||||
m_selected_swap.clear();
|
m_selected_swap.clear();
|
||||||
delete m_selected_item;
|
delete m_selected_item;
|
||||||
m_selected_item = NULL;
|
m_selected_item = nullptr;
|
||||||
m_selected_amount = 0;
|
m_selected_amount = 0;
|
||||||
m_selected_dragging = false;
|
m_selected_dragging = false;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "irrlichttypes_extrabloated.h"
|
#include "irrlichttypes_extrabloated.h"
|
||||||
#include "inventorymanager.h"
|
#include "inventorymanager.h"
|
||||||
#include "modalMenu.h"
|
#include "modalMenu.h"
|
||||||
|
#include "guiInventoryList.h"
|
||||||
#include "guiTable.h"
|
#include "guiTable.h"
|
||||||
#include "network/networkprotocol.h"
|
#include "network/networkprotocol.h"
|
||||||
#include "client/joystick_controller.h"
|
#include "client/joystick_controller.h"
|
||||||
@ -78,51 +79,6 @@ public:
|
|||||||
|
|
||||||
class GUIFormSpecMenu : public GUIModalMenu
|
class GUIFormSpecMenu : public GUIModalMenu
|
||||||
{
|
{
|
||||||
struct ItemSpec
|
|
||||||
{
|
|
||||||
ItemSpec() = default;
|
|
||||||
|
|
||||||
ItemSpec(const InventoryLocation &a_inventoryloc,
|
|
||||||
const std::string &a_listname,
|
|
||||||
s32 a_i) :
|
|
||||||
inventoryloc(a_inventoryloc),
|
|
||||||
listname(a_listname),
|
|
||||||
i(a_i)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isValid() const { return i != -1; }
|
|
||||||
|
|
||||||
InventoryLocation inventoryloc;
|
|
||||||
std::string listname;
|
|
||||||
s32 i = -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ListDrawSpec
|
|
||||||
{
|
|
||||||
ListDrawSpec() = default;
|
|
||||||
|
|
||||||
ListDrawSpec(const InventoryLocation &a_inventoryloc,
|
|
||||||
const std::string &a_listname,
|
|
||||||
IGUIElement *elem, v2s32 a_geom, s32 a_start_item_i,
|
|
||||||
bool a_real_coordinates):
|
|
||||||
inventoryloc(a_inventoryloc),
|
|
||||||
listname(a_listname),
|
|
||||||
e(elem),
|
|
||||||
geom(a_geom),
|
|
||||||
start_item_i(a_start_item_i),
|
|
||||||
real_coordinates(a_real_coordinates)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
InventoryLocation inventoryloc;
|
|
||||||
std::string listname;
|
|
||||||
IGUIElement *e;
|
|
||||||
v2s32 geom;
|
|
||||||
s32 start_item_i;
|
|
||||||
bool real_coordinates;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ListRingSpec
|
struct ListRingSpec
|
||||||
{
|
{
|
||||||
ListRingSpec() = default;
|
ListRingSpec() = default;
|
||||||
@ -186,35 +142,6 @@ class GUIFormSpecMenu : public GUIModalMenu
|
|||||||
irr::video::SColor color;
|
irr::video::SColor color;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StaticTextSpec
|
|
||||||
{
|
|
||||||
StaticTextSpec():
|
|
||||||
parent_button(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
StaticTextSpec(const std::wstring &a_text,
|
|
||||||
const core::rect<s32> &a_rect):
|
|
||||||
text(a_text),
|
|
||||||
rect(a_rect),
|
|
||||||
parent_button(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
StaticTextSpec(const std::wstring &a_text,
|
|
||||||
const core::rect<s32> &a_rect,
|
|
||||||
gui::IGUIButton *a_parent_button):
|
|
||||||
text(a_text),
|
|
||||||
rect(a_rect),
|
|
||||||
parent_button(a_parent_button)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::wstring text;
|
|
||||||
core::rect<s32> rect;
|
|
||||||
gui::IGUIButton *parent_button;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GUIFormSpecMenu(JoystickController *joystick,
|
GUIFormSpecMenu(JoystickController *joystick,
|
||||||
gui::IGUIElement* parent, s32 id,
|
gui::IGUIElement* parent, s32 id,
|
||||||
@ -283,13 +210,37 @@ public:
|
|||||||
m_focused_element = elementname;
|
m_focused_element = elementname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Client *getClient() const
|
||||||
|
{
|
||||||
|
return m_client;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GUIInventoryList::ItemSpec *getSelectedItem() const
|
||||||
|
{
|
||||||
|
return m_selected_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u16 getSelectedAmount() const
|
||||||
|
{
|
||||||
|
return m_selected_amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool doTooltipAppendItemname() const
|
||||||
|
{
|
||||||
|
return m_tooltip_append_itemname;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addHoveredItemTooltip(const std::string &name)
|
||||||
|
{
|
||||||
|
m_hovered_item_tooltips.emplace_back(name);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Remove and re-add (or reposition) stuff
|
Remove and re-add (or reposition) stuff
|
||||||
*/
|
*/
|
||||||
void regenerateGui(v2u32 screensize);
|
void regenerateGui(v2u32 screensize);
|
||||||
|
|
||||||
ItemSpec getItemAtPos(v2s32 p) const;
|
GUIInventoryList::ItemSpec getItemAtPos(v2s32 p) const;
|
||||||
void drawList(const ListDrawSpec &s, int layer, bool &item_hovered);
|
|
||||||
void drawSelectedItem();
|
void drawSelectedItem();
|
||||||
void drawMenu();
|
void drawMenu();
|
||||||
void updateSelectedItem();
|
void updateSelectedItem();
|
||||||
@ -342,7 +293,7 @@ protected:
|
|||||||
std::string m_formspec_prepend;
|
std::string m_formspec_prepend;
|
||||||
InventoryLocation m_current_inventory_location;
|
InventoryLocation m_current_inventory_location;
|
||||||
|
|
||||||
std::vector<ListDrawSpec> m_inventorylists;
|
std::vector<GUIInventoryList *> m_inventorylists;
|
||||||
std::vector<ListRingSpec> m_inventory_rings;
|
std::vector<ListRingSpec> m_inventory_rings;
|
||||||
std::vector<gui::IGUIElement *> m_backgrounds;
|
std::vector<gui::IGUIElement *> m_backgrounds;
|
||||||
std::unordered_map<std::string, bool> field_close_on_enter;
|
std::unordered_map<std::string, bool> field_close_on_enter;
|
||||||
@ -354,7 +305,7 @@ protected:
|
|||||||
std::vector<std::pair<FieldSpec, GUIScrollBar *>> m_scrollbars;
|
std::vector<std::pair<FieldSpec, GUIScrollBar *>> m_scrollbars;
|
||||||
std::vector<std::pair<FieldSpec, std::vector<std::string>>> m_dropdowns;
|
std::vector<std::pair<FieldSpec, std::vector<std::string>>> m_dropdowns;
|
||||||
|
|
||||||
ItemSpec *m_selected_item = nullptr;
|
GUIInventoryList::ItemSpec *m_selected_item = nullptr;
|
||||||
u16 m_selected_amount = 0;
|
u16 m_selected_amount = 0;
|
||||||
bool m_selected_dragging = false;
|
bool m_selected_dragging = false;
|
||||||
ItemStack m_selected_swap;
|
ItemStack m_selected_swap;
|
||||||
@ -374,12 +325,8 @@ protected:
|
|||||||
|
|
||||||
bool m_bgnonfullscreen;
|
bool m_bgnonfullscreen;
|
||||||
bool m_bgfullscreen;
|
bool m_bgfullscreen;
|
||||||
bool m_slotborder;
|
|
||||||
video::SColor m_bgcolor;
|
video::SColor m_bgcolor;
|
||||||
video::SColor m_fullscreen_bgcolor;
|
video::SColor m_fullscreen_bgcolor;
|
||||||
video::SColor m_slotbg_n;
|
|
||||||
video::SColor m_slotbg_h;
|
|
||||||
video::SColor m_slotbordercolor;
|
|
||||||
video::SColor m_default_tooltip_bgcolor;
|
video::SColor m_default_tooltip_bgcolor;
|
||||||
video::SColor m_default_tooltip_color;
|
video::SColor m_default_tooltip_color;
|
||||||
|
|
||||||
@ -406,6 +353,8 @@ private:
|
|||||||
GUITable::TableOptions table_options;
|
GUITable::TableOptions table_options;
|
||||||
GUITable::TableColumns table_columns;
|
GUITable::TableColumns table_columns;
|
||||||
|
|
||||||
|
GUIInventoryList::Options inventorylist_options;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
s32 max = 1000;
|
s32 max = 1000;
|
||||||
s32 min = 0;
|
s32 min = 0;
|
||||||
@ -428,6 +377,7 @@ private:
|
|||||||
|
|
||||||
fs_key_pendig current_keys_pending;
|
fs_key_pendig current_keys_pending;
|
||||||
std::string current_field_enter_pending = "";
|
std::string current_field_enter_pending = "";
|
||||||
|
std::vector<std::string> m_hovered_item_tooltips;
|
||||||
|
|
||||||
void parseElement(parserData* data, const std::string &element);
|
void parseElement(parserData* data, const std::string &element);
|
||||||
|
|
||||||
|
210
src/gui/guiInventoryList.cpp
Normal file
210
src/gui/guiInventoryList.cpp
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
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));
|
||||||
|
|
||||||
|
bool ret = hovered && 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;
|
||||||
|
}
|
130
src/gui/guiInventoryList.h
Normal file
130
src/gui/guiInventoryList.h
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "inventorymanager.h"
|
||||||
|
#include "irrlichttypes_extrabloated.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
|
||||||
|
class GUIFormSpecMenu;
|
||||||
|
|
||||||
|
class GUIInventoryList : public gui::IGUIElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct ItemSpec
|
||||||
|
{
|
||||||
|
ItemSpec() = default;
|
||||||
|
|
||||||
|
ItemSpec(const InventoryLocation &a_inventoryloc,
|
||||||
|
const std::string &a_listname,
|
||||||
|
s32 a_i) :
|
||||||
|
inventoryloc(a_inventoryloc),
|
||||||
|
listname(a_listname),
|
||||||
|
i(a_i)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const { return i != -1; }
|
||||||
|
|
||||||
|
InventoryLocation inventoryloc;
|
||||||
|
std::string listname;
|
||||||
|
s32 i = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// options for inventorylists that are setable with the lua api
|
||||||
|
struct Options {
|
||||||
|
// whether a one-pixel border for the slots should be drawn and its color
|
||||||
|
bool slotborder = false;
|
||||||
|
video::SColor slotbordercolor = video::SColor(200, 0, 0, 0);
|
||||||
|
// colors for normal and highlighted slot background
|
||||||
|
video::SColor slotbg_n = video::SColor(255, 128, 128, 128);
|
||||||
|
video::SColor slotbg_h = video::SColor(255, 192, 192, 192);
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
virtual void draw() override;
|
||||||
|
|
||||||
|
virtual bool OnEvent(const SEvent &event) override;
|
||||||
|
|
||||||
|
const InventoryLocation &getInventoryloc() const
|
||||||
|
{
|
||||||
|
return m_inventoryloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &getListname() const
|
||||||
|
{
|
||||||
|
return m_listname;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSlotBGColors(const video::SColor &slotbg_n, const video::SColor &slotbg_h)
|
||||||
|
{
|
||||||
|
m_options.slotbg_n = slotbg_n;
|
||||||
|
m_options.slotbg_h = slotbg_h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSlotBorders(bool slotborder, const video::SColor &slotbordercolor)
|
||||||
|
{
|
||||||
|
m_options.slotborder = slotborder;
|
||||||
|
m_options.slotbordercolor = slotbordercolor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns -1 if not item is at pos p
|
||||||
|
s32 getItemIndexAtPos(v2s32 p) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
InventoryManager *m_invmgr;
|
||||||
|
const InventoryLocation m_inventoryloc;
|
||||||
|
const std::string m_listname;
|
||||||
|
|
||||||
|
// specifies the width and height of the inventorylist in itemslots
|
||||||
|
const v2s32 m_geom;
|
||||||
|
// the first item's index in inventory
|
||||||
|
const s32 m_start_item_i;
|
||||||
|
|
||||||
|
// specifies how large the slot rects are
|
||||||
|
const v2s32 m_slot_size;
|
||||||
|
// specifies how large the space between slots is (space between is spacing-size)
|
||||||
|
const v2f32 m_slot_spacing;
|
||||||
|
|
||||||
|
// the GUIFormSpecMenu can have an item selected and co.
|
||||||
|
GUIFormSpecMenu *m_fs_menu;
|
||||||
|
|
||||||
|
Options m_options;
|
||||||
|
|
||||||
|
// the font
|
||||||
|
gui::IGUIFont *m_font;
|
||||||
|
|
||||||
|
// the index of the hovered item; -1 if no item is hovered
|
||||||
|
s32 m_hovered_i;
|
||||||
|
};
|
@ -177,6 +177,8 @@ src/gui/guiFormSpecMenu.h
|
|||||||
src/gui/guiKeyChangeMenu.cpp
|
src/gui/guiKeyChangeMenu.cpp
|
||||||
src/gui/guiHyperText.cpp
|
src/gui/guiHyperText.cpp
|
||||||
src/gui/guiHyperText.h
|
src/gui/guiHyperText.h
|
||||||
|
src/gui/guiInventoryList.cpp
|
||||||
|
src/gui/guiInventoryList.h
|
||||||
src/gui/guiItemImage.cpp
|
src/gui/guiItemImage.cpp
|
||||||
src/gui/guiItemImage.h
|
src/gui/guiItemImage.h
|
||||||
src/gui/guiMainMenu.h
|
src/gui/guiMainMenu.h
|
||||||
|
Loading…
Reference in New Issue
Block a user