From c920df748b01f6ecbd98adaf07f6d92c64a7213c Mon Sep 17 00:00:00 2001 From: Kahrl Date: Fri, 13 Jan 2012 12:35:55 +0100 Subject: [PATCH] Inventory menu changes: Tooltips; dragging; drop from menu. Lag is a bit annoying (even in single player). --- data/mods/default/init.lua | 2 +- src/guiInventoryMenu.cpp | 229 ++++++++++++++++++++++++++----------- src/guiInventoryMenu.h | 3 +- src/inventorymanager.cpp | 30 +++-- 4 files changed, 184 insertions(+), 80 deletions(-) diff --git a/data/mods/default/init.lua b/data/mods/default/init.lua index 2bd950230..8093e99d5 100644 --- a/data/mods/default/init.lua +++ b/data/mods/default/init.lua @@ -1284,7 +1284,7 @@ minetest.register_node("default:rail", { }) minetest.register_node("default:ladder", { - dsecription = "Ladder", + description = "Ladder", drawtype = "signlike", tile_images = {"default_ladder.png"}, inventory_image = "default_ladder.png", diff --git a/src/guiInventoryMenu.cpp b/src/guiInventoryMenu.cpp index f2a644e80..6e46bd49c 100644 --- a/src/guiInventoryMenu.cpp +++ b/src/guiInventoryMenu.cpp @@ -133,6 +133,7 @@ GUIInventoryMenu::GUIInventoryMenu(gui::IGUIEnvironment* env, m_gamedef(gamedef) { m_selected_item = NULL; + m_tooltip_element = NULL; } GUIInventoryMenu::~GUIInventoryMenu() @@ -163,6 +164,11 @@ void GUIInventoryMenu::removeChildren() if(e != NULL) e->remove(); }*/ + if(m_tooltip_element) + { + m_tooltip_element->remove(); + m_tooltip_element = NULL; + } } void GUIInventoryMenu::regenerateGui(v2u32 screensize) @@ -227,6 +233,17 @@ void GUIInventoryMenu::regenerateGui(v2u32 screensize) const wchar_t *text = L"Left click: Move all items, Right click: Move single item"; 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(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); } -void GUIInventoryMenu::drawList(const ListDrawSpec &s) +void GUIInventoryMenu::drawList(const ListDrawSpec &s, int phase) { video::IVideoDriver* driver = Environment->getVideoDriver(); @@ -280,40 +297,67 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s) if(ilist) item = ilist->getItem(i); - if(m_selected_item != NULL && m_selected_item->listname == s.listname - && m_selected_item->i == i) + bool selected = m_selected_item + && 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; - driver->draw2DRectangle(video::SColor(255,192,192,192), - core::rect(rect.UpperLeftCorner - v2s32(1,1)*border, - rect.LowerRightCorner + v2s32(1,1)*border), - NULL); - driver->draw2DRectangle(video::SColor(255,0,0,0), - core::rect(rect.UpperLeftCorner - v2s32(1,1)*((border+1)/2), - rect.LowerRightCorner + v2s32(1,1)*((border+1)/2)), - NULL);*/ - s32 border = 2; - driver->draw2DRectangle(video::SColor(255,255,0,0), - core::rect(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(hovering && 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, - rect, &AbsoluteClippingRect, m_gamedef); + // Draw item at the normal position if + // - 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( + core::position2d(tooltip_x, tooltip_y), + core::dimension2d(tooltip_width, tooltip_height))); + } } } @@ -329,13 +373,19 @@ void GUIInventoryMenu::drawMenu() video::SColor bgcolor(140,0,0,0); driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect); + m_tooltip_element->setVisible(false); + /* 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; iisValid()); + 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; else if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN) amount = 1; else if(event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN) amount = 10; - else if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP && - m_selected_item && - (m_selected_item->listname != s.listname - || m_selected_item->i != s.i)) + else if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP && different_item) 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) { + // Indicates whether source slot should be deselected + bool remove_selection = false; + //infostream<<"Mouse action at p=("<getInventory( - m_selected_item->inventoryloc); - Inventory *inv_to = m_invmgr->getInventory( - s.inventoryloc); + Inventory *inv_from = inv_selected; + Inventory *inv_to = inv_s; assert(inv_from); assert(inv_to); InventoryList *list_from = @@ -401,8 +476,6 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event) infostream<<"from list doesn't exist"<getItem(m_selected_item->i).empty()) { @@ -415,18 +488,10 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event) a->to_inv = s.inventoryloc; a->to_list = s.listname; a->to_i = s.i; - //ispec.actions->push_back(a); m_invmgr->inventoryAction(a); - if(list_from->getItem(m_selected_item->i).count<=amount) - source_empties = 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; + if(amount == 0 || list_from->getItem(m_selected_item->i).count<=amount) + remove_selection = true; } } else @@ -434,23 +499,51 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event) /* Select if nonempty */ - Inventory *inv = m_invmgr->getInventory( - s.inventoryloc); - assert(inv); - InventoryList *list = inv->getList(s.listname); - if(!list->getItem(s.i).empty()) + assert(inv_s); + InventoryList *list = inv_s->getList(s.listname); + if(list && !list->getItem(s.i).empty()) { 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; - m_selected_item = NULL; + // Inside menu + 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"<getItem(m_selected_item->i).empty()) + { + infostream<<"Handing IACTION_DROP to manager"<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; } } } diff --git a/src/guiInventoryMenu.h b/src/guiInventoryMenu.h index c3b3e5a64..903a8b137 100644 --- a/src/guiInventoryMenu.h +++ b/src/guiInventoryMenu.h @@ -136,7 +136,7 @@ public: void regenerateGui(v2u32 screensize); ItemSpec getItemAtPos(v2s32 p) const; - void drawList(const ListDrawSpec &s); + void drawList(const ListDrawSpec &s, int phase); void drawMenu(); bool OnEvent(const SEvent& event); @@ -161,6 +161,7 @@ protected: ItemSpec *m_selected_item; v2s32 m_pointer; + gui::IGUIStaticText *m_tooltip_element; }; #endif diff --git a/src/inventorymanager.cpp b/src/inventorymanager.cpp index 0149fd9ab..eeb293cb1 100644 --- a/src/inventorymanager.cpp +++ b/src/inventorymanager.cpp @@ -302,18 +302,28 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player) return; } - /* - Drop the item - */ - ItemStack item = list_from->getItem(from_i); - if(scriptapi_item_on_drop(player->getEnv()->getLua(), item, player, + // Take item from source list + ItemStack item1; + if(count == 0) + item1 = list_from->changeItem(from_i, ItemStack()); + 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))) { - // Apply returned ItemStack - if(g_settings->getBool("creative_mode") == false - || from_inv.type != InventoryLocation::PLAYER) - list_from->changeItem(from_i, item); - mgr->setInventoryModified(from_inv); + if(g_settings->getBool("creative_mode") == true + && from_inv.type == InventoryLocation::PLAYER) + item2 = item1; // creative mode + + 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 "