ManaPlus
itemcontainer.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2004-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2018 The ManaPlus Developers
6  *
7  * This file is part of The ManaPlus Client.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
24 
25 #include "dragdrop.h"
26 #include "settings.h"
27 
28 #include "being/playerinfo.h"
29 
30 #include "gui/gui.h"
31 #include "gui/skin.h"
32 #include "gui/viewport.h"
33 
34 #include "gui/fonts/font.h"
35 
37 
38 #include "gui/popups/itempopup.h"
39 
40 #include "gui/windows/chatwindow.h"
42 #include "gui/windows/shopwindow.h"
46 #include "gui/windows/npcdialog.h"
47 
48 #include "input/inputmanager.h"
49 
50 #include "net/inventoryhandler.h"
51 #include "net/net.h"
52 #include "net/mail2handler.h"
53 #include "net/npchandler.h"
54 #include "net/tradehandler.h"
55 
56 #include "utils/delete2.h"
57 #include "utils/foreach.h"
58 #include "utils/gettext.h"
59 #include "utils/stringutils.h"
60 
62 
63 #include "resources/iteminfo.h"
64 
65 #include <algorithm>
66 
67 #include "debug.h"
68 
69 namespace
70 {
72  {
73  public:
75 
76  ItemIdPair(const int id, Item *const item) :
77  mId(id), mItem(item)
78  {
79  }
80 
81  int mId;
83  };
84 
86  {
87  public:
89 
90  bool operator() (const ItemIdPair *const pair1,
91  const ItemIdPair *const pair2) const
92  {
93  const Item *const item1 = pair1->mItem;
94  const Item *const item2 = pair2->mItem;
95  if ((item1 == nullptr) || (item2 == nullptr))
96  return false;
97 
98  const std::string name1 = item1->getInfo().getName(
99  item1->getColor());
100  const std::string name2 = item2->getInfo().getName(
101  item2->getColor());
102  if (name1 == name2)
103  {
104  return item1->getInvIndex() <
105  item2->getInvIndex();
106  }
107  return name1 < name2;
108  }
110 
112  {
113  public:
115 
116  bool operator() (const ItemIdPair *const pair1,
117  const ItemIdPair *const pair2) const
118  {
119  if ((pair1->mItem == nullptr) || (pair2->mItem == nullptr))
120  return false;
121 
122  const int id1 = pair1->mItem->getId();
123  const int id2 = pair2->mItem->getId();
124  if (id1 == id2)
125  {
126  return pair1->mItem->getInvIndex() <
127  pair2->mItem->getInvIndex();
128  }
129  return id1 < id2;
130  }
131  } itemIdInvSorter;
132 
134  {
135  public:
137 
138  bool operator() (const ItemIdPair *const pair1,
139  const ItemIdPair *const pair2) const
140  {
141  if ((pair1->mItem == nullptr) || (pair2->mItem == nullptr))
142  return false;
143 
144  const int w1 = pair1->mItem->getInfo().getWeight();
145  const int w2 = pair2->mItem->getInfo().getWeight();
146  if (w1 == w2)
147  {
148  const std::string name1 =
149  pair1->mItem->getInfo().getName();
150  const std::string name2 =
151  pair2->mItem->getInfo().getName();
152  if (name1 == name2)
153  {
154  return pair1->mItem->getInvIndex() <
155  pair2->mItem->getInvIndex();
156  }
157  return name1 < name2;
158  }
159  return w1 < w2;
160  }
162 
164  {
165  public:
167 
168  bool operator() (const ItemIdPair *const pair1,
169  const ItemIdPair *const pair2) const
170  {
171  if ((pair1->mItem == nullptr) || (pair2->mItem == nullptr))
172  return false;
173 
174  const int c1 = pair1->mItem->getQuantity();
175  const int c2 = pair2->mItem->getQuantity();
176  if (c1 == c2)
177  {
178  const std::string name1 =
179  pair1->mItem->getInfo().getName();
180  const std::string name2 =
181  pair2->mItem->getInfo().getName();
182  if (name1 == name2)
183  {
184  return pair1->mItem->getInvIndex() <
185  pair2->mItem->getInvIndex();
186  }
187  return name1 < name2;
188  }
189  return c1 < c2;
190  }
192 
194  {
195  public:
197 
198  bool operator() (const ItemIdPair *const pair1,
199  const ItemIdPair *const pair2) const
200  {
201  if ((pair1->mItem == nullptr) || (pair2->mItem == nullptr))
202  return false;
203 
204  const ItemInfo &info1 = pair1->mItem->getInfo();
205  const ItemInfo &info2 = pair2->mItem->getInfo();
206  const ItemDbTypeT t1 = info1.getType();
207  const ItemDbTypeT t2 = info2.getType();
208  if (t1 == t2)
209  {
210  const std::string &name1 = info1.getName();
211  const std::string &name2 = info2.getName();
212  if (name1 == name2)
213  {
214  return pair1->mItem->getInvIndex() <
215  pair2->mItem->getInvIndex();
216  }
217  return name1 < name2;
218  }
219  return t1 < t2;
220  }
222 } // namespace
223 
225  Inventory *const inventory,
226  const int maxColumns,
227  const ShowEmptyRows showEmptyRows,
228  const ForceQuantity forceQuantity) :
229  Widget(widget),
230  KeyListener(),
231  MouseListener(),
232  WidgetListener(),
233  mInventory(inventory),
234  mSelImg(Theme::getImageFromThemeXml("item_selection.xml", "")),
235  mProtectedImg(Theme::getImageFromTheme("lock.png")),
236  mCellBackgroundImg(Theme::getImageFromThemeXml("inventory_cell.xml", "")),
237  mName(),
238  mShowMatrix(nullptr),
239  mSkin(theme != nullptr ? theme->load("itemcontainer.xml", "",
240  true, Theme::getThemePath()) : nullptr),
241  mVertexes(new ImageCollection),
242  mEquipedColor(getThemeColor(ThemeColorId::ITEM_EQUIPPED, 255U)),
243  mEquipedColor2(getThemeColor(ThemeColorId::ITEM_EQUIPPED_OUTLINE, 255U)),
244  mUnEquipedColor(getThemeColor(ThemeColorId::ITEM_NOT_EQUIPPED, 255U)),
245  mUnEquipedColor2(getThemeColor(ThemeColorId::ITEM_NOT_EQUIPPED_OUTLINE,
246  255U)),
247  mSelectionListeners(),
248  mGridColumns(1),
249  mGridRows(1),
250  mDrawRows(1),
251  mSelectedIndex(-1),
252  mLastUsedSlot(-1),
253  mTag(0),
254  mSortType(0),
255  mClicks(1),
256  mBoxWidth(mSkin != nullptr ? mSkin->getOption("boxWidth", 35) : 35),
257  mBoxHeight(mSkin != nullptr ? mSkin->getOption("boxHeight", 43) : 43),
258  mEquippedTextPadding(mSkin != nullptr ? mSkin->getOption(
259  "equippedTextPadding", 29) : 29),
260  mPaddingItemX(mSkin != nullptr ? mSkin->getOption("paddingItemX", 0) : 0),
261  mPaddingItemY(mSkin != nullptr ? mSkin->getOption("paddingItemY", 0) : 0),
262  mMaxColumns(maxColumns),
263  mSelectionStatus(SEL_NONE),
264  mForceQuantity(forceQuantity),
265  mShowEmptyRows(showEmptyRows),
266  mDescItems(false)
267 {
268  setFocusable(true);
269  addKeyListener(this);
270  addMouseListener(this);
271  addWidgetListener(this);
272  mAllowLogic = false;
273 }
274 
276 {
277  if (gui != nullptr)
278  gui->removeDragged(this);
279 
280  if (mSelImg != nullptr)
281  {
282  mSelImg->decRef();
283  mSelImg = nullptr;
284  }
285  if (mProtectedImg != nullptr)
286  {
288  mProtectedImg = nullptr;
289  }
290  if (mCellBackgroundImg != nullptr)
291  {
293  mCellBackgroundImg = nullptr;
294  }
295 
296  if (theme != nullptr)
297  theme->unload(mSkin);
298 
299  delete []mShowMatrix;
301 }
302 
304 {
305  BLOCK_START("ItemContainer::logic")
306  Widget::logic();
307 
308  if (mInventory == nullptr)
309  {
310  BLOCK_END("ItemContainer::logic")
311  return;
312  }
313 
314  const int lastUsedSlot = mInventory->getLastUsedSlot();
315 
316  if (lastUsedSlot != mLastUsedSlot)
317  {
318  mLastUsedSlot = lastUsedSlot;
319  adjustHeight();
320  }
321  BLOCK_END("ItemContainer::logic")
322 }
323 
324 void ItemContainer::draw(Graphics *const graphics)
325 {
326  if ((mInventory == nullptr) || (mShowMatrix == nullptr))
327  return;
328 
329  BLOCK_START("ItemContainer::draw")
330  Font *const font = getFont();
331 
332  if (mCellBackgroundImg != nullptr)
333  {
334  if (mRedraw || graphics->getRedraw())
335  {
336  mRedraw = false;
337  mVertexes->clear();
338 
339  const int invSize = mInventory->getSize();
340  const int maxRows = mShowEmptyRows == ShowEmptyRows_true ?
341  std::max(invSize / mGridColumns, mGridRows) : mGridRows;
342  const int maxColumns = mGridColumns > invSize ?
343  invSize : mGridColumns;
344  for (int j = 0; j < maxRows; j++)
345  {
346  const int intY0 = j * mBoxHeight;
347  for (int i = 0; i < maxColumns; i++)
348  {
349  int itemX = i * mBoxWidth;
350  int itemY = intY0;
351  graphics->calcTileCollection(mVertexes,
353  itemX + mPaddingItemX,
354  itemY + mPaddingItemY);
355  }
356  }
357  graphics->finalize(mVertexes);
358  }
359  graphics->drawTileCollection(mVertexes);
360  }
361 
362  for (int j = 0; j < mDrawRows; j++)
363  {
364  const int intY0 = j * mBoxHeight;
365  int itemIndex = j * mGridColumns - 1;
366  for (int i = 0; i < mGridColumns; i++)
367  {
368  int itemX = i * mBoxWidth;
369  int itemY = intY0;
370  itemIndex ++;
371  if (mShowMatrix[itemIndex] < 0)
372  continue;
373 
374  const Item *const item = mInventory->getItem(
375  mShowMatrix[itemIndex]);
376 
377  if ((item == nullptr) || item->getId() == 0)
378  continue;
379 
380  Image *const image = item->getImage();
381  if (image != nullptr)
382  {
383  if (mShowMatrix[itemIndex] == mSelectedIndex)
384  {
385  if (mSelImg != nullptr)
386  graphics->drawImage(mSelImg, itemX, itemY);
387  }
388  image->setAlpha(1.0F); // ensure the image if fully drawn...
389  graphics->drawImage(image,
390  itemX + mPaddingItemX,
391  itemY + mPaddingItemY);
392  if ((mProtectedImg != nullptr) && PlayerInfo::isItemProtected(
393  item->getId()))
394  {
395  graphics->drawImage(mProtectedImg,
396  itemX + mPaddingItemX,
397  itemY + mPaddingItemY);
398  }
399  }
400  }
401  }
402 
403  for (int j = 0; j < mDrawRows; j++)
404  {
405  const int intY0 = j * mBoxHeight;
406  int itemIndex = j * mGridColumns - 1;
407  for (int i = 0; i < mGridColumns; i++)
408  {
409  int itemX = i * mBoxWidth;
410  int itemY = intY0;
411  itemIndex ++;
412  if (mShowMatrix[itemIndex] < 0)
413  continue;
414 
415  const Item *const item = mInventory->getItem(
416  mShowMatrix[itemIndex]);
417 
418  if ((item == nullptr) || item->getId() == 0)
419  continue;
420 
421  // Draw item caption
422  std::string caption;
423  if (item->getQuantity() > 1 ||
425  {
426  caption = toString(item->getQuantity());
427  }
428  else if (item->isEquipped() == Equipped_true)
429  {
430  // TRANSLATORS: Text under equipped items (should be small)
431  caption = _("Eq.");
432  }
433 
434  if (item->isEquipped() == Equipped_true)
435  {
436  font->drawString(graphics,
438  caption,
439  itemX + (mBoxWidth - font->getWidth(caption)) / 2,
440  itemY + mEquippedTextPadding);
441  }
442  else
443  {
444  font->drawString(graphics,
446  caption,
447  itemX + (mBoxWidth - font->getWidth(caption)) / 2,
448  itemY + mEquippedTextPadding);
449  }
450  }
451  }
452  BLOCK_END("ItemContainer::draw")
453 }
454 
455 void ItemContainer::safeDraw(Graphics *const graphics)
456 {
457  if ((mInventory == nullptr) || (mShowMatrix == nullptr))
458  return;
459 
460  BLOCK_START("ItemContainer::draw")
461  Font *const font = getFont();
462 
463  if (mCellBackgroundImg != nullptr)
464  {
465  const int invSize = mInventory->getSize();
466  const int maxRows = mShowEmptyRows == ShowEmptyRows_true ?
467  std::max(invSize / mGridColumns, mGridRows) : mGridRows;
468  const int maxColumns = mGridColumns > invSize ?
469  invSize : mGridColumns;
470  for (int j = 0; j < maxRows; j++)
471  {
472  const int intY0 = j * mBoxHeight;
473  for (int i = 0; i < maxColumns; i++)
474  {
475  int itemX = i * mBoxWidth;
476  int itemY = intY0;
477  graphics->drawImage(mCellBackgroundImg,
478  itemX + mPaddingItemX,
479  itemY + mPaddingItemY);
480  }
481  }
482  }
483 
484  for (int j = 0; j < mDrawRows; j++)
485  {
486  const int intY0 = j * mBoxHeight;
487  int itemIndex = j * mGridColumns - 1;
488  for (int i = 0; i < mGridColumns; i++)
489  {
490  int itemX = i * mBoxWidth;
491  int itemY = intY0;
492  itemIndex ++;
493  if (mShowMatrix[itemIndex] < 0)
494  continue;
495 
496  const Item *const item = mInventory->getItem(
497  mShowMatrix[itemIndex]);
498 
499  if ((item == nullptr) || item->getId() == 0)
500  continue;
501 
502  Image *const image = item->getImage();
503  if (image != nullptr)
504  {
505  if (mShowMatrix[itemIndex] == mSelectedIndex)
506  {
507  if (mSelImg != nullptr)
508  graphics->drawImage(mSelImg, itemX, itemY);
509  }
510  image->setAlpha(1.0F); // ensure the image if fully drawn...
511  graphics->drawImage(image,
512  itemX + mPaddingItemX,
513  itemY + mPaddingItemY);
514  if ((mProtectedImg != nullptr) && PlayerInfo::isItemProtected(
515  item->getId()))
516  {
517  graphics->drawImage(mProtectedImg,
518  itemX + mPaddingItemX,
519  itemY + mPaddingItemY);
520  }
521  }
522  }
523  }
524 
525  for (int j = 0; j < mDrawRows; j++)
526  {
527  const int intY0 = j * mBoxHeight;
528  int itemIndex = j * mGridColumns - 1;
529  for (int i = 0; i < mGridColumns; i++)
530  {
531  int itemX = i * mBoxWidth;
532  int itemY = intY0;
533  itemIndex ++;
534  if (mShowMatrix[itemIndex] < 0)
535  continue;
536 
537  const Item *const item = mInventory->getItem(
538  mShowMatrix[itemIndex]);
539 
540  if ((item == nullptr) || item->getId() == 0)
541  continue;
542 
543  // Draw item caption
544  std::string caption;
545  if (item->getQuantity() > 1 ||
547  {
548  caption = toString(item->getQuantity());
549  }
550  else if (item->isEquipped() == Equipped_true)
551  {
552  // TRANSLATORS: Text under equipped items (should be small)
553  caption = _("Eq.");
554  }
555 
556  if (item->isEquipped() == Equipped_true)
557  {
558  font->drawString(graphics,
560  caption,
561  itemX + (mBoxWidth - font->getWidth(caption)) / 2,
562  itemY + mEquippedTextPadding);
563  }
564  else
565  {
566  font->drawString(graphics,
568  caption,
569  itemX + (mBoxWidth - font->getWidth(caption)) / 2,
570  itemY + mEquippedTextPadding);
571  }
572  }
573  }
574  BLOCK_END("ItemContainer::draw")
575 }
576 
578 {
579  dragDrop.clear();
580 
581  setSelectedIndex(-1);
583 /*
584  if (outfitWindow)
585  outfitWindow->setItemSelected(-1);
586  if (shopWindow)
587  shopWindow->setItemSelected(-1);
588 */
589 }
590 
591 void ItemContainer::setSelectedIndex(const int newIndex)
592 {
593  if (mSelectedIndex != newIndex)
594  {
595  mSelectedIndex = newIndex;
597  }
598 }
599 
601 {
602  if (mInventory != nullptr)
604  return nullptr;
605 }
606 
608 {
610  {
611  if (*i != nullptr)
612  {
613  SelectionEvent event(this);
614  (*i)->valueChanged(event);
615  }
616  }
617 }
618 
620 {
621 }
622 
624 {
625 }
626 
628 {
629  if (mInventory == nullptr)
630  return;
631 
632  const MouseButtonT button = event.getButton();
633  mClicks = event.getClickCount();
634 
635  if (button == MouseButton::LEFT || button == MouseButton::RIGHT)
636  {
637  event.consume();
638  const int index = getSlotIndex(event.getX(), event.getY());
639  if (index == Inventory::NO_SLOT_INDEX)
640  return;
641 
642  Item *const item = mInventory->getItem(index);
643 
644  // put item name into chat window
645  if ((item != nullptr) && mDescItems && (chatWindow != nullptr))
647 
649  switch (mInventory->getType())
650  {
653  break;
656  break;
658  src = DragDropSource::Trade;
659  break;
660  case InventoryType::Npc:
661  src = DragDropSource::Npc;
662  break;
663  case InventoryType::Cart:
664  src = DragDropSource::Cart;
665  break;
668  break;
671  break;
673  src = DragDropSource::Craft;
674  break;
675  default:
678  break;
679  }
680  if (src == DragDropSource::MailView)
681  return;
682  if (mSelectedIndex == index && mClicks != 2)
683  {
684  dragDrop.dragItem(item, src, index);
685  dragDrop.select(item);
687  }
688  else if ((item != nullptr) && (item->getId() != 0))
689  {
690  if (index >= 0)
691  {
692  dragDrop.dragItem(item, src, index);
693  dragDrop.select(item);
694  setSelectedIndex(index);
696 
697  if (itemShortcutWindow != nullptr)
698  {
699  const int num = itemShortcutWindow->getTabIndex();
700  if (num >= 0 && num < CAST_S32(SHORTCUT_TABS))
701  {
702  if (itemShortcut[num] != nullptr)
703  itemShortcut[num]->setItemSelected(item);
704  }
705  }
706  if (shopWindow != nullptr)
707  shopWindow->setItemSelected(item->getId());
708  }
709  }
710  else
711  {
712  dragDrop.deselect();
713  selectNone();
714  }
715  }
716 }
717 
719 {
720  if (mSelectionStatus != SEL_NONE)
722 }
723 
725 {
726  if (mClicks == 2 ||
727  inventoryHandler == nullptr ||
728  tradeHandler == nullptr)
729  {
730  return;
731  }
732 
733  switch (mSelectionStatus)
734  {
735  case SEL_SELECTING:
737  break;
738  case SEL_DESELECTING:
739  selectNone();
740  break;
741  case SEL_DRAGGING:
743  break;
744  case SEL_NONE:
745  case SEL_SELECTED:
746  default:
747  break;
748  };
749 
750  if (dragDrop.isEmpty())
751  {
752  const int index = getSlotIndex(event.getX(), event.getY());
753  if (index == Inventory::NO_SLOT_INDEX)
754  return;
755  if (index == mSelectedIndex || mSelectedIndex == -1)
756  return;
758  selectNone();
759  }
760  else if (mInventory != nullptr)
761  {
762  const DragDropSourceT src = dragDrop.getSource();
764  switch (mInventory->getType())
765  {
768  break;
771  break;
773  dst = DragDropSource::Trade;
774  break;
775  case InventoryType::Npc:
776  dst = DragDropSource::Npc;
777  break;
780  break;
783  break;
784  case InventoryType::Cart:
785  dst = DragDropSource::Cart;
786  break;
788  dst = DragDropSource::Craft;
789  break;
790  default:
793  break;
794  }
795  InventoryTypeT srcContainer = InventoryType::TypeEnd;
796  InventoryTypeT dstContainer = InventoryType::TypeEnd;
797  bool checkProtection(false);
798  Inventory *inventory = nullptr;
799  if (src == DragDropSource::Inventory
800  && dst == DragDropSource::Storage)
801  {
802  srcContainer = InventoryType::Inventory;
803  dstContainer = InventoryType::Storage;
804  inventory = PlayerInfo::getInventory();
805  }
806  else if (src == DragDropSource::Storage
807  && dst == DragDropSource::Inventory)
808  {
809  srcContainer = InventoryType::Storage;
810  dstContainer = InventoryType::Inventory;
811  inventory = PlayerInfo::getStorageInventory();
812  }
813  if (src == DragDropSource::Inventory
814  && dst == DragDropSource::Cart)
815  {
816  srcContainer = InventoryType::Inventory;
817  dstContainer = InventoryType::Cart;
818  inventory = PlayerInfo::getInventory();
819  }
820  if (src == DragDropSource::Inventory
821  && dst == DragDropSource::Inventory)
822  {
824  return;
825  const int index = getSlotIndex(event.getX(), event.getY());
826  if (index == Inventory::NO_SLOT_INDEX)
827  return;
828  if (index == mSelectedIndex || mSelectedIndex == -1)
829  return;
830  if (inventoryWindow != nullptr)
832  return;
833  }
834  else if (src == DragDropSource::Cart
835  && dst == DragDropSource::Inventory)
836  {
837  srcContainer = InventoryType::Cart;
838  dstContainer = InventoryType::Inventory;
839  inventory = PlayerInfo::getCartInventory();
840  }
841  else if (src == DragDropSource::Cart
842  && dst == DragDropSource::Storage)
843  {
844  srcContainer = InventoryType::Cart;
845  dstContainer = InventoryType::Storage;
846  inventory = PlayerInfo::getCartInventory();
847  }
848  else if (src == DragDropSource::Storage
849  && dst == DragDropSource::Cart)
850  {
851  srcContainer = InventoryType::Storage;
852  dstContainer = InventoryType::Cart;
853  inventory = PlayerInfo::getStorageInventory();
854  }
855  if (src == DragDropSource::Inventory
856  && dst == DragDropSource::Trade)
857  {
858  checkProtection = true;
859  inventory = PlayerInfo::getInventory();
860  }
861  else if (src == DragDropSource::Inventory &&
862  dst == DragDropSource::Npc)
863  {
864  inventory = PlayerInfo::getInventory();
865  if (inventory != nullptr)
866  {
867  Item *const item = inventory->getItem(dragDrop.getTag());
869  item,
870  getSlotByXY(event.getX(), event.getY()),
871  1))
872  {
873  inventory->virtualRemove(item, 1);
874  }
875  }
876  return;
877  }
878  else if (src == DragDropSource::Inventory &&
880  {
881  inventory = PlayerInfo::getInventory();
882  if (inventory == nullptr)
883  return;
884  Item *const item = inventory->getItem(dragDrop.getTag());
885  if (item == nullptr)
886  return;
888  {
889  if (item->getQuantity() > 1
891  {
895  item,
896  0,
897  0);
898  }
899  else
900  {
901  mail2Handler->addItem(item, 1);
902  }
903  }
904  else
905  {
907  item,
908  getSlotByXY(event.getX(), event.getY()),
909  1))
910  {
911  inventory->virtualRemove(item, 1);
912  }
913  }
914  return;
915  }
916  else if (src == DragDropSource::Npc)
917  {
918  inventory = PlayerInfo::getInventory();
919  if (dst == DragDropSource::Npc)
920  {
921  const Item *const item = mInventory->getItem(
922  dragDrop.getTag());
923  const int index = getSlotByXY(event.getX(), event.getY());
924  if (index == Inventory::NO_SLOT_INDEX)
925  {
926  if (inventory != nullptr)
927  inventory->virtualRestore(item, 1);
929  return;
930  }
931  mInventory->removeItemAt(index);
932  mInventory->setItem(index,
933  item->getId(),
934  item->getType(),
935  1,
936  1,
937  item->getColor(),
938  item->getIdentified(),
939  item->getDamaged(),
940  item->getFavorite(),
941  Equipm_false,
943  Item *const item2 = mInventory->getItem(index);
944  if (item2 != nullptr)
945  item2->setTag(item->getTag());
947  }
948  else
949  {
950  if (inventory != nullptr)
951  {
952  const Item *const item = inventory->getItem(
953  dragDrop.getTag());
954  if (item != nullptr)
955  {
956  inventory->virtualRestore(item, 1);
958  }
959  }
960  return;
961  }
962  }
963  else if (src == DragDropSource::Inventory &&
964  dst == DragDropSource::Craft)
965  {
966  inventory = PlayerInfo::getInventory();
967  if (inventory != nullptr)
968  {
969  Item *const item = inventory->getItem(dragDrop.getTag());
970  if ((item == nullptr) || item->isEquipped() == Equipped_true)
971  return;
972  const int slot = getSlotByXY(event.getX(), event.getY());
973  if (item->getQuantity() > 1
975  {
979  item,
980  0,
981  slot);
982  }
983  else
984  {
986  item,
987  slot,
988  1))
989  {
990  inventory->virtualRemove(item, 1);
991  }
992  }
993  }
994  return;
995  }
996  else if (src == DragDropSource::Craft)
997  {
998  inventory = PlayerInfo::getInventory();
999  if (dst == DragDropSource::Craft)
1000  {
1001  const Item *const item = mInventory->getItem(
1002  dragDrop.getTag());
1003  const int index = getSlotByXY(event.getX(), event.getY());
1004  if (index == Inventory::NO_SLOT_INDEX)
1005  {
1006  if (inventory != nullptr)
1007  {
1008  inventory->virtualRestore(item,
1009  item->getQuantity());
1011  }
1012  return;
1013  }
1014  mInventory->moveItem(index, dragDrop.getTag());
1015  }
1016  else
1017  {
1018  if (inventory != nullptr)
1019  {
1020  const Item *const item = inventory->getItem(
1021  dragDrop.getTag());
1022  if (item != nullptr)
1023  {
1024  inventory->virtualRestore(item,
1025  item->getQuantity());
1027  }
1028  }
1029  return;
1030  }
1031  }
1032  else if (src == DragDropSource::MailEdit)
1033  {
1034  if (event.getType() == MouseEventType::RELEASED2)
1035  return;
1037  {
1038  if (mailEditWindow == nullptr)
1039  return;
1040  inventory = mailEditWindow->getInventory();
1041  if (inventory == nullptr)
1042  return;
1043  const Item *const item = inventory->getItem(dragDrop.getTag());
1044  if (item == nullptr)
1045  return;
1046  mail2Handler->removeItem(item->getTag(),
1047  item->getQuantity());
1048  }
1049  else
1050  {
1051  inventory = PlayerInfo::getInventory();
1052  if (inventory == nullptr)
1053  return;
1054  const Item *const item = inventory->getItem(dragDrop.getTag());
1055  if (item == nullptr)
1056  return;
1058  }
1059  return;
1060  }
1061 
1062  if (inventory != nullptr)
1063  {
1064  const Item *const item = inventory->getItem(dragDrop.getTag());
1065  if (item != nullptr)
1066  {
1067  if (srcContainer != InventoryType::TypeEnd)
1068  { // inventory <--> storage, cart
1069  inventoryHandler->moveItem2(srcContainer,
1070  item->getInvIndex(),
1071  item->getQuantity(),
1072  dstContainer);
1073  }
1074  else
1075  { // inventory --> trade
1076  if (!checkProtection || !PlayerInfo::isItemProtected(
1077  item->getId()))
1078  {
1079  tradeHandler->addItem(item, item->getQuantity());
1080  }
1081  }
1082  }
1083  }
1084  }
1085 }
1086 
1088 {
1089  if (mInventory == nullptr)
1090  return;
1091 
1092  const Item *const item = mInventory->getItem(
1093  getSlotIndex(event.getX(), event.getY()));
1094 
1095  if ((item != nullptr) && (viewport != nullptr))
1096  {
1097  itemPopup->setItem(item, false);
1099  }
1100  else
1101  {
1103  }
1104 }
1105 
1107 {
1109 }
1110 
1112 {
1113  updateSize();
1114 }
1115 
1117 {
1118  mGridColumns = std::min(mMaxColumns,
1119  std::max(1, mDimension.width / mBoxWidth));
1120  if (mGridColumns > mMaxColumns)
1122  adjustHeight();
1123  mRedraw = true;
1124 }
1125 
1127 {
1128  mRedraw = true;
1129 }
1130 
1132 {
1133  if (mGridColumns == 0)
1134  return;
1135 
1137  if (mGridRows == 0 || (mLastUsedSlot + 1) % mGridColumns > 0)
1138  ++mGridRows;
1139 
1140  const int invSize = mInventory->getSize();
1141  int maxRows = mShowEmptyRows == ShowEmptyRows_true ?
1142  std::max(invSize / mGridColumns, mGridRows) : mGridRows;
1143 
1145  {
1146  if (mGridColumns * maxRows < invSize)
1147  maxRows ++;
1148  mGridRows = maxRows;
1149  }
1150 
1151  const int num = updateMatrix();
1153  {
1154  mDrawRows = num / mGridColumns;
1155  if (mDrawRows == 0 || num % mGridColumns > 0)
1156  ++mDrawRows;
1157 
1158  maxRows = mDrawRows;
1159  }
1160  else
1161  {
1162  mDrawRows = mGridRows;
1163  }
1164  setHeight(maxRows * mBoxHeight);
1165 }
1166 
1168 {
1169  if (mInventory == nullptr)
1170  return 0;
1171 
1172  mRedraw = true;
1173  delete []mShowMatrix;
1175 
1176  STD_VECTOR<ItemIdPair*> sortedItems;
1177  int i = 0;
1178  int j = 0;
1179 
1180  std::string temp = mName;
1181  toLower(temp);
1182 
1183  const unsigned int invSize = mInventory->getSize();
1184  for (unsigned int idx = 0; idx < invSize; idx ++)
1185  {
1186  Item *const item = mInventory->getItem(idx);
1187 
1188  if (item == nullptr ||
1189  item->getId() == 0 ||
1190  !item->isHaveTag(mTag) ||
1191  item->getQuantity() == 0)
1192  {
1194  sortedItems.push_back(new ItemIdPair(idx, nullptr));
1195  continue;
1196  }
1197 
1198  if (!item->isHaveTag(mTag))
1199  continue;
1200 
1201  if (mName.empty())
1202  {
1203  sortedItems.push_back(new ItemIdPair(idx, item));
1204  continue;
1205  }
1206  std::string name = item->getInfo().getName();
1207  toLower(name);
1208  if (name.find(temp) != std::string::npos)
1209  sortedItems.push_back(new ItemIdPair(idx, item));
1210  }
1211 
1212  switch (mSortType)
1213  {
1214  case 0:
1215  default:
1216  break;
1217  case 1:
1218  std::sort(sortedItems.begin(), sortedItems.end(),
1220  break;
1221  case 2:
1222  std::sort(sortedItems.begin(), sortedItems.end(), itemIdInvSorter);
1223  break;
1224  case 3:
1225  std::sort(sortedItems.begin(), sortedItems.end(),
1227  break;
1228  case 4:
1229  std::sort(sortedItems.begin(), sortedItems.end(),
1231  break;
1232  case 5:
1233  std::sort(sortedItems.begin(), sortedItems.end(),
1235  break;
1236  }
1237 
1238  int jMult = j * mGridColumns;
1239  const int maxSize = mGridRows * mGridColumns;
1240  FOR_EACH (STD_VECTOR<ItemIdPair*>::const_iterator, iter, sortedItems)
1241  {
1242  if (jMult >= maxSize)
1243  break;
1244 
1245  mShowMatrix[jMult + i] = (*iter)->mId;
1246 
1247  i ++;
1248  if (i >= mGridColumns)
1249  {
1250  i = 0;
1251  j ++;
1252  jMult += mGridColumns;
1253  }
1254  }
1255 
1256  for (int idx = j * mGridColumns + i; idx < maxSize; idx ++)
1257  mShowMatrix[idx] = -1;
1258 
1259  const int num = CAST_S32(sortedItems.size());
1260  for (size_t idx = 0, sz = num; idx < sz; idx ++)
1261  delete sortedItems[idx];
1262  return num;
1263 }
1264 
1265 int ItemContainer::getSlotIndex(int x, int y) const
1266 {
1267  if (mShowMatrix == nullptr)
1268  return Inventory::NO_SLOT_INDEX;
1269 
1270  if (x < mDimension.width && y < mDimension.height && x >= 0 && y >= 0)
1271  {
1272  if (x > mBoxWidth * mGridColumns)
1273  return Inventory::NO_SLOT_INDEX;
1274  const int idx = (y / mBoxHeight) * mGridColumns + (x / mBoxWidth);
1275  if (idx >= 0 && idx < mGridRows * mGridColumns
1276  && mShowMatrix[idx] >= 0)
1277  {
1278  return mShowMatrix[idx];
1279  }
1280  }
1281 
1282  return Inventory::NO_SLOT_INDEX;
1283 }
1284 
1285 int ItemContainer::getSlotByXY(int x, int y) const
1286 {
1287  if (mShowMatrix == nullptr)
1288  return Inventory::NO_SLOT_INDEX;
1289 
1290  if (x < mDimension.width && y < mDimension.height && x >= 0 && y >= 0)
1291  {
1292  if (x > mBoxWidth * mGridColumns)
1293  return Inventory::NO_SLOT_INDEX;
1294  const int idx = (y / mBoxHeight) * mGridColumns + (x / mBoxWidth);
1295  if (idx >= 0 && idx < mGridRows * mGridColumns)
1296  return idx;
1297  }
1298 
1299  return Inventory::NO_SLOT_INDEX;
1300 }
1301 
1302 void ItemContainer::setFilter(const int tag)
1303 {
1304  mTag = tag;
1305  adjustHeight();
1306 }
1307 
1308 void ItemContainer::setSortType(const int sortType)
1309 {
1310  mSortType = sortType;
1311  updateMatrix();
1312 }
1313 
1314 void ItemContainer::setCellBackgroundImage(const std::string &xmlName)
1315 {
1316  if (mCellBackgroundImg != nullptr)
1319  mRedraw = true;
1320 }
1321 
1322 void ItemContainer::setMaxColumns(const int maxColumns)
1323 {
1324  mMaxColumns = maxColumns;
1325  updateSize();
1326 }
#define A_DELETE_COPY(func)
Definition: localconsts.h:52
int getInvIndex() const
Definition: item.h:164
Font * getFont() const
Definition: widget.cpp:330
ChatWindow * chatWindow
Definition: chatwindow.cpp:89
#define FOR_EACH(type, iter, array)
Definition: foreach.h:24
ForceQuantity mForceQuantity
Color mUnEquipedColor2
#define _(s)
Definition: gettext.h:34
void widgetResized(const Event &event)
virtual void moveItem2(const InventoryTypeT source, const int slot, const int amount, const InventoryTypeT destination) const =0
int width
Definition: rect.h:218
const bool ShowEmptyRows_true
Definition: showemptyrows.h:29
void setItemSelected(const int itemId)
Definition: itemshortcut.h:125
int getTag() const
Definition: item.h:230
int getTag() const
Definition: dragdrop.h:234
SelectionListenerList mSelectionListeners
class anonymous_namespace{itemcontainer.cpp}::SortItemIdFunctor itemIdInvSorter
virtual void drawTileCollection(const ImageCollection *const vertCol)=0
void unload(Skin *const skin)
Definition: theme.cpp:249
DragDropSource ::T DragDropSourceT
Gui * gui
Definition: gui.cpp:110
Definition: font.h:88
SelectionListenerList::iterator SelectionListenerIterator
Item * getSelectedItem() const
const bool ShowEmptyRows_false
Definition: showemptyrows.h:29
void mouseReleased(MouseEvent &event)
InventoryType ::T InventoryTypeT
Definition: inventorytype.h:41
void clear()
Definition: dragdrop.h:182
void setVisible(Visible visible)
Definition: widget.cpp:224
Equipped isEquipped() const
Definition: item.h:128
static Image * getImageFromThemeXml(const std::string &name, const std::string &name2)
Definition: theme.cpp:925
void widgetMoved(const Event &event)
Inventory * getInventory()
Definition: playerinfo.cpp:192
#define BLOCK_START(name)
Definition: perfomance.h:78
class anonymous_namespace{itemcontainer.cpp}::SortItemAlphaFunctor itemAlphaInvSorter
#define final
Definition: localconsts.h:45
virtual void addItem(const Item *const item, const int amount) const =0
static void showWindow(const ItemAmountWindowUsageT usage, Window *const parent, Item *const item, int maxRange, const int tag)
std::string mName
DragDrop dragDrop
#define BLOCK_END(name)
Definition: perfomance.h:79
void virtualRemove(Item *const item, const int amount)
Definition: inventory.cpp:484
void safeDraw(Graphics *const graphics)
class anonymous_namespace{itemcontainer.cpp}::SortItemTypeFunctor itemTypeInvSorter
int mMouseX
Definition: viewport.h:153
ItemContainer(const Widget2 *const widget, Inventory *const inventory, const int maxColumns, const ShowEmptyRows showEmptyRows, const ForceQuantity forceQuantity)
const std::string & getName() const
Definition: iteminfo.h:73
#define delete2(var)
Definition: delete2.h:24
void moveItem(const int index1, const int index2)
Definition: inventory.cpp:536
Net::Mail2Handler * mail2Handler
Definition: net.cpp:108
const bool Equipped_true
Definition: equipped.h:29
bool isEmpty() const
Definition: dragdrop.h:195
virtual void addItem(const Item *const item, const int amount) const
Definition: tradehandler.h:51
InventoryWindow * inventoryWindow
static const int NO_SLOT_INDEX
Definition: inventory.h:57
Damaged getDamaged() const
Definition: item.h:198
void removeItemAt(const int index)
Definition: inventory.cpp:253
const bool Equipped_false
Definition: equipped.h:29
void dragItem(const Item *const item, const DragDropSourceT source, const int tag)
Definition: dragdrop.h:86
bool isActionActive(const InputActionT index) const
class anonymous_namespace{itemcontainer.cpp}::SortItemAmountFunctor itemAmountInvSorter
virtual bool addVirtualItem(const Item *const item, int index, const int amount)
Definition: inventory.cpp:438
#define A_DEFAULT_COPY(func)
Definition: localconsts.h:40
virtual void removeItem(const int index, const int amount) const =0
virtual void finalize(ImageCollection *const col)
Definition: graphics.h:464
#define new
Definition: debug_new.h:147
virtual NpcDialog * getCurrentNpcDialog() const =0
Settings settings
Definition: settings.cpp:31
virtual void setAlpha(const float alpha)
Definition: image.cpp:286
void setCellBackgroundImage(const std::string &xmlName)
Inventory * getCartInventory()
Definition: playerinfo.cpp:204
#define CAST_S32
Definition: cast.h:29
int getTabIndex() const
const bool Visible_false
Definition: visible.h:29
int getQuantity() const
Definition: item.h:104
void keyPressed(KeyEvent &event)
virtual void setItem(const int index, const int id, const ItemTypeT type, const int quantity, const uint8_t refine, const ItemColor color, const Identified identified, const Damaged damaged, const Favorite favorite, const Equipm equipment, const Equipped equipped)
Definition: inventory.cpp:140
ImageCollection * mVertexes
void setTag(const int tag)
Definition: item.h:227
virtual void logic()
Definition: widget.h:192
void mousePressed(MouseEvent &event)
void position(const int x, const int y)
Definition: popup.cpp:232
void drawString(Graphics *const graphics, Color col, const Color &col2, const std::string &text, const int x, const int y)
Definition: font.cpp:253
void combineItems(const int index1, const int index2)
ItemColor getColor() const
Definition: item.h:180
void mouseExited(MouseEvent &event)
Definition: item.h:48
std::string toLower(std::string const &s)
Inventory * getStorageInventory()
Definition: playerinfo.cpp:197
#define nullptr
Definition: localconsts.h:44
bool mAllowLogic
Definition: widget.h:1159
void setMaxColumns(const int maxColumns)
void deselect()
Definition: dragdrop.h:212
void addMouseListener(MouseListener *const mouseListener)
Definition: widget.cpp:291
ShortcutWindow * itemShortcutWindow
Definition: theme.h:52
const unsigned int SHORTCUT_TABS
Definition: itemshortcut.h:27
const ItemInfo & getInfo() const
Definition: item.h:170
void addKeyListener(KeyListener *const keyListener)
Definition: widget.cpp:271
Image * mCellBackgroundImg
void setItem(const ItemInfo &item, const ItemColor color, const bool showImage, int id, const int *const cards, const ItemOptionsList *const options)
Definition: itempopup.cpp:188
bool getRedraw() const
Definition: graphics.h:286
Color mUnEquipedColor
ShowEmptyRows mShowEmptyRows
void keyReleased(KeyEvent &event)
ItemShortcut * itemShortcut[SHORTCUT_TABS]
Net::InventoryHandler * inventoryHandler
Definition: net.cpp:85
Inventory * mInventory
Definition: playerinfo.cpp:57
int mMouseY
Definition: viewport.h:154
void draw(Graphics *const graphics)
Inventory * mInventory
void setHeight(const int height)
Definition: widget.cpp:139
void addWidgetListener(WidgetListener *const widgetListener)
Definition: widget.cpp:301
ShopWindow * shopWindow
Definition: shopwindow.cpp:100
ServerTypeT getNetworkType()
Definition: net.cpp:182
MouseEventTypeT getType() const
Definition: mouseevent.h:154
bool isItemProtected(const int id)
Definition: playerinfo.cpp:511
class anonymous_namespace{itemcontainer.cpp}::SortItemWeightFunctor itemWeightInvSorter
std::string toString(T const &value)
converts any type to a string
Definition: catch.hpp:1774
int getId() const
Definition: item.h:80
Theme * theme
Definition: theme.cpp:61
#define A_UNUSED
Definition: localconsts.h:151
void setFocusable(const bool focusable)
Definition: widget.cpp:191
Image * getImage() const
Definition: item.h:86
virtual void drawImage(const Image *const image, int dstX, int dstY)=0
void removeDragged(const Widget *const widget)
Definition: gui.cpp:1160
Definition: widget.h:97
void setSelectedIndex(const int index)
Net::TradeHandler * tradeHandler
Definition: net.cpp:94
Identified getIdentified() const
Definition: item.h:192
int getWidth(const std::string &text) const
Definition: font.cpp:333
Definition: event.h:77
bool mRedraw
Definition: widget.h:1163
ItemTypeT getType() const
Definition: item.h:224
ItemDbTypeT getType() const
Definition: iteminfo.h:126
Definition: image.h:61
virtual void calcTileCollection(ImageCollection *const vertCol, const Image *const image, int x, int y)=0
void setSortType(const int sortType)
void setItemSelected(const int id)
Definition: shopwindow.h:106
void addItemText(const std::string &item)
int mEquippedTextPadding
void distributeValueChangedEvent()
Net::NpcHandler * npcHandler
Definition: net.cpp:89
#define CAST_SIZE
Definition: cast.h:33
int getX() const
Definition: mouseevent.h:126
InputManager inputManager
bool isHaveTag(const int tagId) const
Definition: item.cpp:118
void select(const Item *const item)
Definition: dragdrop.h:198
MailEditWindow * mailEditWindow
DragDropSourceT getSource() const
Definition: dragdrop.h:83
int getSlotIndex(int x, int y) const
Image * mProtectedImg
virtual void moveItem(const int oldIndex, const int newIndex) const =0
ItemPopup * itemPopup
Definition: itempopup.cpp:63
SelectionState mSelectionStatus
Item * getItem(const int index) const
Definition: inventory.cpp:82
int getSlotByXY(int x, int y) const
MouseButton ::T MouseButtonT
Definition: mousebutton.h:77
Rect mDimension
Definition: widget.h:1100
void mouseMoved(MouseEvent &event)
InventoryTypeT getType() const
Definition: inventory.h:175
bool enableNewMailSystem
Definition: settings.h:161
const bool ForceQuantity_true
Definition: forcequantity.h:29
void decRef()
Definition: image.cpp:522
void setFilter(const int tag)
Inventory * getInventory() const
ItemDbType ::T ItemDbTypeT
Definition: itemdbtype.h:48
int getLastUsedSlot() const
Definition: inventory.cpp:290
Color mEquipedColor2
Viewport * viewport
Definition: viewport.cpp:35
void mouseDragged(MouseEvent &event)
const bool Equipm_false
Definition: equipm.h:29
void virtualRestore(const Item *const item, const int amount)
Definition: inventory.cpp:516
unsigned getSize() const
Definition: inventory.h:75
Favorite getFavorite() const
Definition: item.h:204