Inventory menu changes: Tooltips; dragging; drop from menu. Lag is a bit annoying (even in single player).

master
Kahrl 2012-01-13 12:35:55 +01:00
parent a58d725569
commit c920df748b
4 changed files with 184 additions and 80 deletions

View File

@ -1284,7 +1284,7 @@ minetest.register_node("default:rail", {
}) })
minetest.register_node("default:ladder", { minetest.register_node("default:ladder", {
dsecription = "Ladder", description = "Ladder",
drawtype = "signlike", drawtype = "signlike",
tile_images = {"default_ladder.png"}, tile_images = {"default_ladder.png"},
inventory_image = "default_ladder.png", inventory_image = "default_ladder.png",

View File

@ -133,6 +133,7 @@ GUIInventoryMenu::GUIInventoryMenu(gui::IGUIEnvironment* env,
m_gamedef(gamedef) m_gamedef(gamedef)
{ {
m_selected_item = NULL; m_selected_item = NULL;
m_tooltip_element = NULL;
} }
GUIInventoryMenu::~GUIInventoryMenu() GUIInventoryMenu::~GUIInventoryMenu()
@ -163,6 +164,11 @@ void GUIInventoryMenu::removeChildren()
if(e != NULL) if(e != NULL)
e->remove(); e->remove();
}*/ }*/
if(m_tooltip_element)
{
m_tooltip_element->remove();
m_tooltip_element = NULL;
}
} }
void GUIInventoryMenu::regenerateGui(v2u32 screensize) void GUIInventoryMenu::regenerateGui(v2u32 screensize)
@ -227,6 +233,17 @@ void GUIInventoryMenu::regenerateGui(v2u32 screensize)
const wchar_t *text = const wchar_t *text =
L"Left click: Move all items, Right click: Move single item"; L"Left click: Move all items, Right click: Move single item";
Environment->addStaticText(text, rect, false, true, this, 256); Environment->addStaticText(text, rect, false, true, this, 256);
// Add tooltip
// Note: parent != this so that the tooltip isn't clipped by the menu rectangle
m_tooltip_element = Environment->addStaticText(L"",core::rect<s32>(0,0,110,18));
m_tooltip_element->enableOverrideColor(true);
m_tooltip_element->setBackgroundColor(video::SColor(255,110,130,60));
m_tooltip_element->setDrawBackground(true);
m_tooltip_element->setDrawBorder(true);
m_tooltip_element->setOverrideColor(video::SColor(255,255,255,255));
m_tooltip_element->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
m_tooltip_element->setWordWrap(false);
} }
} }
@ -254,7 +271,7 @@ GUIInventoryMenu::ItemSpec GUIInventoryMenu::getItemAtPos(v2s32 p) const
return ItemSpec(InventoryLocation(), "", -1); return ItemSpec(InventoryLocation(), "", -1);
} }
void GUIInventoryMenu::drawList(const ListDrawSpec &s) void GUIInventoryMenu::drawList(const ListDrawSpec &s, int phase)
{ {
video::IVideoDriver* driver = Environment->getVideoDriver(); video::IVideoDriver* driver = Environment->getVideoDriver();
@ -280,40 +297,67 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s)
if(ilist) if(ilist)
item = ilist->getItem(i); item = ilist->getItem(i);
if(m_selected_item != NULL && m_selected_item->listname == s.listname bool selected = m_selected_item
&& m_selected_item->i == i) && m_invmgr->getInventory(m_selected_item->inventoryloc) == inv
&& m_selected_item->listname == s.listname
&& m_selected_item->i == i;
bool hovering = rect.isPointInside(m_pointer);
if(phase == 0)
{ {
/*s32 border = imgsize.X/12; if(hovering && m_selected_item)
driver->draw2DRectangle(video::SColor(255,192,192,192), {
core::rect<s32>(rect.UpperLeftCorner - v2s32(1,1)*border, video::SColor bgcolor(255,192,192,192);
rect.LowerRightCorner + v2s32(1,1)*border), driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
NULL); }
driver->draw2DRectangle(video::SColor(255,0,0,0), else
core::rect<s32>(rect.UpperLeftCorner - v2s32(1,1)*((border+1)/2), {
rect.LowerRightCorner + v2s32(1,1)*((border+1)/2)), video::SColor bgcolor(255,128,128,128);
NULL);*/ driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
s32 border = 2; }
driver->draw2DRectangle(video::SColor(255,255,0,0),
core::rect<s32>(rect.UpperLeftCorner - v2s32(1,1)*border,
rect.LowerRightCorner + v2s32(1,1)*border),
&AbsoluteClippingRect);
}
if(rect.isPointInside(m_pointer) && m_selected_item)
{
video::SColor bgcolor(255,192,192,192);
driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
}
else
{
video::SColor bgcolor(255,128,128,128);
driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
} }
if(!item.empty()) if(phase == 1 && !item.empty())
{ {
drawItemStack(driver, font, item, // Draw item at the normal position if
rect, &AbsoluteClippingRect, m_gamedef); // - the item is not being dragged or
// /*- the item is in the crafting result slot*/
if(!selected /*|| s.listname == "craftresult"*/)
{
drawItemStack(driver, font, item,
rect, &AbsoluteClippingRect, m_gamedef);
}
}
if(phase ==2 && !item.empty())
{
// Draw dragged item
if(selected)
{
v2s32 offset = m_pointer - rect.getCenter();
rect.UpperLeftCorner += offset;
rect.LowerRightCorner += offset;
drawItemStack(driver, font, item,
rect, NULL, m_gamedef);
}
// Draw tooltip
std::string tooltip_text = "";
if(hovering && !m_selected_item)
tooltip_text = item.getDefinition(m_gamedef->idef()).description;
if(tooltip_text != "")
{
m_tooltip_element->setVisible(true);
this->bringToFront(m_tooltip_element);
m_tooltip_element->setText(narrow_to_wide(tooltip_text).c_str());
s32 tooltip_x = m_pointer.X + 15;
s32 tooltip_y = m_pointer.Y + 15;
s32 tooltip_width = m_tooltip_element->getTextWidth() + 15;
s32 tooltip_height = m_tooltip_element->getTextHeight() + 5;
m_tooltip_element->setRelativePosition(core::rect<s32>(
core::position2d<s32>(tooltip_x, tooltip_y),
core::dimension2d<s32>(tooltip_width, tooltip_height)));
}
} }
} }
@ -329,13 +373,19 @@ void GUIInventoryMenu::drawMenu()
video::SColor bgcolor(140,0,0,0); video::SColor bgcolor(140,0,0,0);
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect); driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
m_tooltip_element->setVisible(false);
/* /*
Draw items Draw items
Phase 0: Item slot rectangles
Phase 1: Item images
Phase 2: Dragged item image; tooltip
*/ */
for(int phase=0; phase<=2; phase++)
for(u32 i=0; i<m_draw_spec.size(); i++) for(u32 i=0; i<m_draw_spec.size(); i++)
{ {
drawList(m_draw_spec[i]); drawList(m_draw_spec[i], phase);
} }
/* /*
@ -356,30 +406,57 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
return true; return true;
} }
} }
if(event.EventType==EET_MOUSE_INPUT_EVENT) if(event.EventType==EET_MOUSE_INPUT_EVENT
&& event.MouseInput.Event == EMIE_MOUSE_MOVED)
{ {
char amount = -1; // Mouse moved
m_pointer = v2s32(event.MouseInput.X, event.MouseInput.Y);
}
if(event.EventType==EET_MOUSE_INPUT_EVENT
&& event.MouseInput.Event != EMIE_MOUSE_MOVED)
{
// Mouse event other than movement
v2s32 p(event.MouseInput.X, event.MouseInput.Y); v2s32 p(event.MouseInput.X, event.MouseInput.Y);
ItemSpec s = getItemAtPos(p); ItemSpec s = getItemAtPos(p);
if(event.MouseInput.Event==EMIE_MOUSE_MOVED) Inventory *inv_selected = NULL;
m_pointer = v2s32(event.MouseInput.X, event.MouseInput.Y); Inventory *inv_s = NULL;
else if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) if(m_selected_item)
{
assert(m_selected_item->isValid());
inv_selected = m_invmgr->getInventory(m_selected_item->inventoryloc);
assert(inv_selected);
}
if(s.isValid())
{
inv_s = m_invmgr->getInventory(s.inventoryloc);
assert(inv_s);
}
bool different_item = m_selected_item
&& ((inv_selected != inv_s)
|| (m_selected_item->listname != s.listname)
|| (m_selected_item->i != s.i));
int amount = -1;
if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
amount = 0; amount = 0;
else if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN) else if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
amount = 1; amount = 1;
else if(event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN) else if(event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN)
amount = 10; amount = 10;
else if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP && else if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP && different_item)
m_selected_item &&
(m_selected_item->listname != s.listname
|| m_selected_item->i != s.i))
amount = 0; amount = 0;
//else if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP && different_item)
// amount = 1;
//else if(event.MouseInput.Event == EMIE_MMOUSE_LEFT_UP && different_item)
// amount = 10;
if(amount >= 0) if(amount >= 0)
{ {
// Indicates whether source slot should be deselected
bool remove_selection = false;
//infostream<<"Mouse action at p=("<<p.X<<","<<p.Y<<")"<<std::endl; //infostream<<"Mouse action at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
if(s.isValid()) if(s.isValid())
{ {
@ -387,10 +464,8 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
<<"/"<<s.listname<<" "<<s.i<<std::endl; <<"/"<<s.listname<<" "<<s.i<<std::endl;
if(m_selected_item) if(m_selected_item)
{ {
Inventory *inv_from = m_invmgr->getInventory( Inventory *inv_from = inv_selected;
m_selected_item->inventoryloc); Inventory *inv_to = inv_s;
Inventory *inv_to = m_invmgr->getInventory(
s.inventoryloc);
assert(inv_from); assert(inv_from);
assert(inv_to); assert(inv_to);
InventoryList *list_from = InventoryList *list_from =
@ -401,8 +476,6 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
infostream<<"from list doesn't exist"<<std::endl; infostream<<"from list doesn't exist"<<std::endl;
if(list_to == NULL) if(list_to == NULL)
infostream<<"to list doesn't exist"<<std::endl; infostream<<"to list doesn't exist"<<std::endl;
// Indicates whether source slot completely empties
bool source_empties = false;
if(list_from && list_to if(list_from && list_to
&& !list_from->getItem(m_selected_item->i).empty()) && !list_from->getItem(m_selected_item->i).empty())
{ {
@ -415,18 +488,10 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
a->to_inv = s.inventoryloc; a->to_inv = s.inventoryloc;
a->to_list = s.listname; a->to_list = s.listname;
a->to_i = s.i; a->to_i = s.i;
//ispec.actions->push_back(a);
m_invmgr->inventoryAction(a); m_invmgr->inventoryAction(a);
if(list_from->getItem(m_selected_item->i).count<=amount) if(amount == 0 || list_from->getItem(m_selected_item->i).count<=amount)
source_empties = true; remove_selection = true;
}
// Remove selection if target was left-clicked or source
// slot was emptied
if(amount == 0 || source_empties)
{
delete m_selected_item;
m_selected_item = NULL;
} }
} }
else else
@ -434,23 +499,51 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
/* /*
Select if nonempty Select if nonempty
*/ */
Inventory *inv = m_invmgr->getInventory( assert(inv_s);
s.inventoryloc); InventoryList *list = inv_s->getList(s.listname);
assert(inv); if(list && !list->getItem(s.i).empty())
InventoryList *list = inv->getList(s.listname);
if(!list->getItem(s.i).empty())
{ {
m_selected_item = new ItemSpec(s); m_selected_item = new ItemSpec(s);
} }
} }
} }
else else if(m_selected_item)
{ {
if(m_selected_item) // If moved outside the menu, drop.
// (Otherwise abort inventory action.)
if(getAbsoluteClippingRect().isPointInside(m_pointer))
{ {
delete m_selected_item; // Inside menu
m_selected_item = NULL; remove_selection = true;
} }
else
{
// Outside of menu
Inventory *inv_from = inv_selected;
assert(inv_from);
InventoryList *list_from =
inv_from->getList(m_selected_item->listname);
if(list_from == NULL)
infostream<<"from list doesn't exist"<<std::endl;
if(list_from && !list_from->getItem(m_selected_item->i).empty())
{
infostream<<"Handing IACTION_DROP to manager"<<std::endl;
IDropAction *a = new IDropAction();
a->count = amount;
a->from_inv = m_selected_item->inventoryloc;
a->from_list = m_selected_item->listname;
a->from_i = m_selected_item->i;
m_invmgr->inventoryAction(a);
if(amount == 0 || list_from->getItem(m_selected_item->i).count<=amount)
remove_selection = true;
}
}
}
if(remove_selection)
{
delete m_selected_item;
m_selected_item = NULL;
} }
} }
} }

View File

@ -136,7 +136,7 @@ public:
void regenerateGui(v2u32 screensize); void regenerateGui(v2u32 screensize);
ItemSpec getItemAtPos(v2s32 p) const; ItemSpec getItemAtPos(v2s32 p) const;
void drawList(const ListDrawSpec &s); void drawList(const ListDrawSpec &s, int phase);
void drawMenu(); void drawMenu();
bool OnEvent(const SEvent& event); bool OnEvent(const SEvent& event);
@ -161,6 +161,7 @@ protected:
ItemSpec *m_selected_item; ItemSpec *m_selected_item;
v2s32 m_pointer; v2s32 m_pointer;
gui::IGUIStaticText *m_tooltip_element;
}; };
#endif #endif

View File

@ -302,18 +302,28 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player)
return; return;
} }
/* // Take item from source list
Drop the item ItemStack item1;
*/ if(count == 0)
ItemStack item = list_from->getItem(from_i); item1 = list_from->changeItem(from_i, ItemStack());
if(scriptapi_item_on_drop(player->getEnv()->getLua(), item, player, else
item1 = list_from->takeItem(from_i, count);
// Drop the item and apply the returned ItemStack
ItemStack item2 = item1;
if(scriptapi_item_on_drop(player->getEnv()->getLua(), item2, player,
player->getBasePosition() + v3f(0,1,0))) player->getBasePosition() + v3f(0,1,0)))
{ {
// Apply returned ItemStack if(g_settings->getBool("creative_mode") == true
if(g_settings->getBool("creative_mode") == false && from_inv.type == InventoryLocation::PLAYER)
|| from_inv.type != InventoryLocation::PLAYER) item2 = item1; // creative mode
list_from->changeItem(from_i, item);
mgr->setInventoryModified(from_inv); list_from->addItem(from_i, item2);
// Unless we have put the same amount back as we took in the first place,
// set inventory modified flag
if(item2.count != item1.count)
mgr->setInventoryModified(from_inv);
} }
infostream<<"IDropAction::apply(): dropped " infostream<<"IDropAction::apply(): dropped "