Mana
Loading...
Searching...
No Matches
itemcontainer.cpp
Go to the documentation of this file.
1/*
2 * The Mana Client
3 * Copyright (C) 2004-2009 The Mana World Development Team
4 * Copyright (C) 2009-2012 The Mana Developers
5 *
6 * This file is part of The Mana Client.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
23
24#include "graphics.h"
25#include "inventory.h"
26#include "item.h"
27#include "itemshortcut.h"
28
29#include "gui/chatwindow.h"
30#include "gui/itempopup.h"
31#include "gui/outfitwindow.h"
32#include "gui/viewport.h"
33
34#include "resources/image.h"
35#include "resources/iteminfo.h"
36#include "resources/theme.h"
37
38#include "utils/stringutils.h"
39
40#include <guichan/mouseinput.hpp>
41#include <guichan/selectionlistener.hpp>
42
43// TODO: Add support for adding items to the item shortcut window (global
44// itemShortcut).
45
47 mInventory(inventory)
48{
50 setFocusable(true);
51
52 addKeyListener(this);
53 addMouseListener(this);
54 addWidgetListener(this);
55}
56
61
63{
64 gcn::Widget::logic();
65
66 const int lastUsedSlot = mInventory->getLastUsedSlot();
67
68 if (lastUsedSlot != mLastUsedSlot)
69 {
70 mLastUsedSlot = lastUsedSlot;
72 }
73}
74
75void ItemContainer::draw(gcn::Graphics *graphics)
76{
77 auto *g = static_cast<Graphics*>(graphics);
78
79 g->setFont(getFont());
80
81 mFilteredMap.clear();
82 int currentIndex = 0;
83 //Filter checking
84 for (int i = 0; i < mGridColumns; i++)
85 {
86 for (int j = 0; j < mGridRows; j++)
87 {
88 int itemIndex = j * mGridColumns + i;
89 Item *item = mInventory->getItem(itemIndex);
90 if (!item || item->getId() == 0)
91 continue;
92
93 if (!mFilter.empty())
94 {
95 if (normalize(item->getInfo().name).find(mFilter) == std::string::npos)
96 continue;
97 mFilteredMap[currentIndex] = item;
98 currentIndex++;
99 }
100 else
101 {
102 mFilteredMap[itemIndex] = item;
103 }
104 }
105 }
106
107 auto theme = gui->getTheme();
108 auto &slotSkin = theme->getSkin(SkinType::ItemSlot);
109 WidgetState slotState;
110
111 for (int i = 0; i < mGridColumns; i++)
112 {
113 for (int j = 0; j < mGridRows; j++)
114 {
115 int itemX = i * slotSkin.width;
116 int itemY = j * slotSkin.height;
117 int itemIndex = j * mGridColumns + i;
118
119 slotState.x = itemX;
120 slotState.y = itemY;
121 slotState.flags = 0;
122
123 if (itemIndex == mSelectedIndex)
124 {
125 slotState.flags |= STATE_SELECTED;
126
128 {
129 // Reposition the coords to that of the cursor.
130 itemX = mDragPosX - (slotSkin.width / 2);
131 itemY = mDragPosY - (slotSkin.height / 2);
132 }
133 }
134
135 slotSkin.draw(g, slotState);
136
137 Item *item = getItemAt(itemIndex);
138
139 if (!item || item->getId() == 0)
140 continue;
141
142 if (Image *image = item->getImage())
143 {
144 image->setAlpha(1.0f);
145 g->drawImage(image, itemX + slotSkin.padding, itemY + slotSkin.padding);
146 }
147
148 // Draw item caption
149 std::string caption;
150 if (item->getQuantity() > 1)
151 caption = toString(item->getQuantity());
152 else if (item->isEquipped())
153 caption = "Eq.";
154
155 if (item->isEquipped())
156 g->setColor(theme->getColor(Theme::ITEM_EQUIPPED));
157 else
158 g->setColor(theme->getColor(Theme::TEXT));
159
160 g->drawText(caption, itemX + slotSkin.width / 2,
161 itemY + slotSkin.height - 14, gcn::Graphics::CENTER);
162 }
163 }
164
165 // Draw an orange box around the selected item
166 if (isFocused() && mHighlightedIndex != -1)
167 {
168 const int itemX = (mHighlightedIndex % mGridColumns) * slotSkin.width;
169 const int itemY = (mHighlightedIndex / mGridColumns) * slotSkin.height;
170 g->setColor(gcn::Color(255, 128, 0));
171 g->drawRectangle(gcn::Rectangle(itemX, itemY, slotSkin.width, slotSkin.height));
172 }
173}
174
181
183{
184 if (mSelectedIndex != newIndex)
185 {
186 mSelectedIndex = newIndex;
188 }
189}
190
195
197{
198 auto i = mFilteredMap.find(index);
199 return i == mFilteredMap.end() ? 0 : i->second;
200}
201
202void ItemContainer::setFilter(const std::string &filter)
203{
204 mFilter = normalize(filter);
205}
206
208{
209 for (auto listener : mSelectionListeners)
210 {
211 gcn::SelectionEvent event(this);
212 listener->valueChanged(event);
213 }
214}
215
217{
218 mItemPopup->setVisible(false);
219}
220
221void ItemContainer::keyPressed(gcn::KeyEvent &event)
222{
223 /*switch (event.getKey().getValue())
224 {
225 case Key::LEFT:
226 moveHighlight(Left);
227 break;
228 case Key::RIGHT:
229 moveHighlight(Right);
230 break;
231 case Key::UP:
232 moveHighlight(Up);
233 break;
234 case Key::DOWN:
235 moveHighlight(Down);
236 break;
237 case Key::SPACE:
238 keyAction();
239 break;
240 case Key::LEFT_ALT:
241 case Key::RIGHT_ALT:
242 mSwapItems = true;
243 break;
244 case Key::RIGHT_CONTROL:
245 mDescItems = true;
246 break;
247 }*/
248}
249
250void ItemContainer::keyReleased(gcn::KeyEvent &event)
251{
252 /*switch (event.getKey().getValue())
253 {
254 case Key::LEFT_ALT:
255 case Key::RIGHT_ALT:
256 mSwapItems = false;
257 break;
258 case Key::RIGHT_CONTROL:
259 mDescItems = false;
260 break;
261 }*/
262}
263
264void ItemContainer::mousePressed(gcn::MouseEvent &event)
265{
266 const int button = event.getButton();
267 if (button == gcn::MouseEvent::LEFT || button == gcn::MouseEvent::RIGHT)
268 {
269 const int index = getSlotIndex(event.getX(), event.getY());
270 if (index == Inventory::NO_SLOT_INDEX)
271 {
273 return;
274 }
275
276 Item *item = getItemAt(index);
277
278 if (!item)
279 {
281 return;
282 }
283
284
285 // put item name into chat window
286 if (mDescItems)
287 {
289 }
290
291 if (mSelectedIndex == index)
292 {
293 }
294 else if (item && item->getId())
295 {
296 setSelectedIndex(index);
299
300 if (item->isEquippable())
302 }
303 else
304 {
305 selectNone();
306 }
307 }
308}
309
310void ItemContainer::mouseDragged(gcn::MouseEvent &event)
311{
313 {
315 mDragPosX = event.getX();
316 mDragPosY = event.getY();
317 }
318}
319
320void ItemContainer::mouseReleased(gcn::MouseEvent &event)
321{
322 switch (mSelectionStatus)
323 {
324 case SEL_SELECTING:
326 return;
327 case SEL_DESELECTING:
328 selectNone();
329 return;
330 case SEL_DRAGGING:
332 break;
333 default:
334 return;
335 };
336
337 int index = getSlotIndex(event.getX(), event.getY());
338 if (index == Inventory::NO_SLOT_INDEX)
339 return;
340 if (index == mSelectedIndex || mSelectedIndex == -1)
341 return;
342
343 Item *item = getSelectedItem();
344 {
345 Event event(Event::DoMove);
346 event.setItem("item", item);
347 event.setInt("newIndex", index);
348 event.trigger(Event::ItemChannel);
349 }
350 selectNone();
351}
352
353
354// Show ItemTooltip
355void ItemContainer::mouseMoved(gcn::MouseEvent &event)
356{
357 if (Item *item = getItemAt(getSlotIndex(event.getX(), event.getY())))
358 {
359 mItemPopup->setItem(item->getInfo());
361 }
362 else
363 {
364 mItemPopup->setVisible(false);
365 }
366}
367
368// Hide ItemTooltip
369void ItemContainer::mouseExited(gcn::MouseEvent &event)
370{
371 mItemPopup->setVisible(false);
372}
373
374void ItemContainer::widgetResized(const gcn::Event &event)
375{
376 auto &slotSkin = gui->getTheme()->getSkin(SkinType::ItemSlot);
377
378 mGridColumns = std::max(1, getWidth() / slotSkin.width);
379 adjustHeight();
380}
381
383{
384 auto &slotSkin = gui->getTheme()->getSkin(SkinType::ItemSlot);
385
387 if (mGridRows == 0 || (mLastUsedSlot + 1) % mGridColumns > 0)
388 ++mGridRows;
389
390 setHeight(mGridRows * slotSkin.height);
391}
392
393int ItemContainer::getSlotIndex(int x, int y) const
394{
395 if (x >= getWidth() || y >= getHeight())
397
398 auto &slotSkin = gui->getTheme()->getSkin(SkinType::ItemSlot);
399 const auto row = y / slotSkin.height;
400 const auto column = x / slotSkin.width;
401
402 if (row < 0 || row >= mGridRows || column < 0 || column >= mGridColumns)
404
405 return (row * mGridColumns) + column;
406}
407
409{
410 // If there is no highlight then return.
411 if (mHighlightedIndex == -1)
412 return;
413
414 // If the highlight is on the selected item, then deselect it.
416 {
417 selectNone();
418 }
419 // Check and swap items if necessary.
420 else if (mSwapItems &&
421 mSelectedIndex != -1 &&
422 mHighlightedIndex != -1)
423 {
424 Item *item = getSelectedItem();
425 Event event(Event::DoMove);
426 event.setItem("item", item);
427 event.setInt("newIndex", mHighlightedIndex);
428 event.trigger(Event::ItemChannel);
430 }
431 // If the highlight is on an item then select it.
432 else if (mHighlightedIndex != -1)
433 {
436 }
437 // If the highlight is on a blank space then move it.
438 else if (mSelectedIndex != -1)
439 {
440 Item *item = getSelectedItem();
441 Event event(Event::DoMove);
442 event.setItem("item", item);
443 event.setInt("newIndex", mHighlightedIndex);
444 event.trigger(Event::ItemChannel);
445 selectNone();
446 }
447}
448
450{
451 if (mHighlightedIndex == -1)
452 {
453 if (mSelectedIndex != -1)
455 else
457 return;
458 }
459
460 switch (direction)
461 {
462 case Left:
466 break;
467 case Right:
469 (mGridColumns - 1))
470 {
472 }
474 break;
475 case Up:
479 break;
480 case Down:
482 (mGridRows - 1))
483 {
485 }
487 break;
488 }
489}
void addItemText(const std::string &item)
Called to add item to chat.
Definition event.h:42
@ DoMove
Definition event.h:77
@ ItemChannel
Definition event.h:53
A central point of control for graphics.
Definition graphics.h:78
Theme * getTheme() const
The global GUI theme.
Definition gui.h:138
Defines a class for loading and storing images.
Definition image.h:45
int getLastUsedSlot() const
Returns the index of the last occupied slot or 0 if none occupied.
Item * getItem(int index) const
Returns the item at the specified index.
Definition inventory.cpp:44
static const int NO_SLOT_INDEX
Slot has no index.
Definition inventory.h:45
int getSlotIndex(int x, int y) const
Gets the slot index based on the cursor position.
void widgetResized(const gcn::Event &event) override
void setSelectedIndex(int index)
Sets the currently selected item.
SelectionState mSelectionStatus
void mouseExited(gcn::MouseEvent &event) override
void setFilter(const std::string &filter)
Sets item filter.
void mouseMoved(gcn::MouseEvent &event) override
Item * getItemAt(int) const
void keyReleased(gcn::KeyEvent &event) override
void keyPressed(gcn::KeyEvent &event) override
~ItemContainer() override
void logic() override
Necessary for checking how full the inventory is.
std::list< gcn::SelectionListener * > mSelectionListeners
void mousePressed(gcn::MouseEvent &event) override
void mouseReleased(gcn::MouseEvent &event) override
ItemPopup * mItemPopup
Item * getSelectedItem() const
Returns the selected item.
void selectNone()
Sets selected item to NULL.
void moveHighlight(Direction direction)
Moves the highlight in the direction specified.
void distributeValueChangedEvent()
Sends out selection events to the list of selection listeners.
Inventory * mInventory
void draw(gcn::Graphics *graphics) override
Draws the items.
std::string mFilter
void adjustHeight()
Determine and set the height of the container.
ItemContainer(Inventory *inventory)
Constructor.
void keyAction()
Execute all the functionality associated with the action key.
std::map< int, Item * > mFilteredMap
void mouseDragged(gcn::MouseEvent &event) override
std::string name
Definition iteminfo.h:113
A popup that displays information about an item.
Definition itempopup.h:39
void setItem(const ItemInfo &item, bool showImage=false)
Sets the info to be displayed given a particular item.
void setItemSelected(int itemId)
Set the item that is selected.
Represents one or more instances of a certain item type.
Definition item.h:35
bool isEquipped() const
Returns whether this item is equipped.
Definition item.h:79
int getQuantity() const
Returns the number of items.
Definition item.h:69
int getId() const
Returns the item id.
Definition item.h:49
Image * getImage() const
Returns the item image.
Definition item.h:54
bool isEquippable() const
Returns whether this item is equippable.
Definition item.cpp:69
const ItemInfo & getInfo() const
Returns information about this item type.
Definition item.h:103
void setItemSelected(int itemId)
void position(int x, int y)
Sets the location to display the popup.
Definition popup.cpp:183
int height
Definition theme.h:181
const Skin & getSkin(SkinType skinType) const
Definition theme.cpp:434
@ ITEM_EQUIPPED
Definition theme.h:235
@ TEXT
Definition theme.h:214
int getMouseY() const
Returns mouse y in pixels.
Definition viewport.h:136
int getMouseX() const
Returns mouse x in pixels.
Definition viewport.h:131
Graphics * graphics
Definition client.cpp:104
OutfitWindow * outfitWindow
Definition game.cpp:106
ChatWindow * chatWindow
Definition game.cpp:93
Viewport * viewport
Viewport on the map.
Definition game.cpp:115
Gui * gui
The GUI system.
Definition gui.cpp:50
ItemShortcut * itemShortcut
std::string normalize(const std::string &name)
Normalize a string, which means lowercase and trim it.
std::string toString(const T &arg)
Converts the given value to a string using std::stringstream.
Definition stringutils.h:68
uint8_t flags
Definition theme.h:150
int width
Definition theme.h:148
@ STATE_SELECTED
Definition theme.h:106