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-2017 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", "") : nullptr),
240  mVertexes(new ImageCollection),
241  mEquipedColor(getThemeColor(ThemeColorId::ITEM_EQUIPPED)),
242  mEquipedColor2(getThemeColor(ThemeColorId::ITEM_EQUIPPED_OUTLINE)),
243  mUnEquipedColor(getThemeColor(ThemeColorId::ITEM_NOT_EQUIPPED)),
244  mUnEquipedColor2(getThemeColor(ThemeColorId::ITEM_NOT_EQUIPPED_OUTLINE)),
245  mSelectionListeners(),
246  mGridColumns(1),
247  mGridRows(1),
248  mDrawRows(1),
249  mSelectedIndex(-1),
250  mLastUsedSlot(-1),
251  mTag(0),
252  mSortType(0),
253  mClicks(1),
254  mBoxWidth(mSkin != nullptr ? mSkin->getOption("boxWidth", 35) : 35),
255  mBoxHeight(mSkin != nullptr ? mSkin->getOption("boxHeight", 43) : 43),
256  mEquippedTextPadding(mSkin != nullptr ? mSkin->getOption(
257  "equippedTextPadding", 29) : 29),
258  mPaddingItemX(mSkin != nullptr ? mSkin->getOption("paddingItemX", 0) : 0),
259  mPaddingItemY(mSkin != nullptr ? mSkin->getOption("paddingItemY", 0) : 0),
260  mMaxColumns(maxColumns),
261  mSelectionStatus(SEL_NONE),
262  mForceQuantity(forceQuantity),
263  mShowEmptyRows(showEmptyRows),
264  mDescItems(false)
265 {
266  setFocusable(true);
267  addKeyListener(this);
268  addMouseListener(this);
269  addWidgetListener(this);
270  mAllowLogic = false;
271 }
272 
274 {
275  if (gui != nullptr)
276  gui->removeDragged(this);
277 
278  if (mSelImg != nullptr)
279  {
280  mSelImg->decRef();
281  mSelImg = nullptr;
282  }
283  if (mProtectedImg != nullptr)
284  {
286  mProtectedImg = nullptr;
287  }
288  if (mCellBackgroundImg != nullptr)
289  {
291  mCellBackgroundImg = nullptr;
292  }
293 
294  if (theme != nullptr)
295  theme->unload(mSkin);
296 
297  delete []mShowMatrix;
299 }
300 
302 {
303  BLOCK_START("ItemContainer::logic")
304  Widget::logic();
305 
306  if (mInventory == nullptr)
307  {
308  BLOCK_END("ItemContainer::logic")
309  return;
310  }
311 
312  const int lastUsedSlot = mInventory->getLastUsedSlot();
313 
314  if (lastUsedSlot != mLastUsedSlot)
315  {
316  mLastUsedSlot = lastUsedSlot;
317  adjustHeight();
318  }
319  BLOCK_END("ItemContainer::logic")
320 }
321 
322 void ItemContainer::draw(Graphics *const graphics)
323 {
324  if ((mInventory == nullptr) || (mShowMatrix == nullptr))
325  return;
326 
327  BLOCK_START("ItemContainer::draw")
328  Font *const font = getFont();
329 
330  if (mCellBackgroundImg != nullptr)
331  {
332  if (mRedraw || graphics->getRedraw())
333  {
334  mRedraw = false;
335  mVertexes->clear();
336 
337  const int invSize = mInventory->getSize();
338  const int maxRows = mShowEmptyRows == ShowEmptyRows_true ?
339  std::max(invSize / mGridColumns, mGridRows) : mGridRows;
340  const int maxColumns = mGridColumns > invSize ?
341  invSize : mGridColumns;
342  for (int j = 0; j < maxRows; j++)
343  {
344  const int intY0 = j * mBoxHeight;
345  for (int i = 0; i < maxColumns; i++)
346  {
347  int itemX = i * mBoxWidth;
348  int itemY = intY0;
349  graphics->calcTileCollection(mVertexes,
351  itemX + mPaddingItemX,
352  itemY + mPaddingItemY);
353  }
354  }
355  graphics->finalize(mVertexes);
356  }
357  graphics->drawTileCollection(mVertexes);
358  }
359 
360  for (int j = 0; j < mDrawRows; j++)
361  {
362  const int intY0 = j * mBoxHeight;
363  int itemIndex = j * mGridColumns - 1;
364  for (int i = 0; i < mGridColumns; i++)
365  {
366  int itemX = i * mBoxWidth;
367  int itemY = intY0;
368  itemIndex ++;
369  if (mShowMatrix[itemIndex] < 0)
370  continue;
371 
372  const Item *const item = mInventory->getItem(
373  mShowMatrix[itemIndex]);
374 
375  if ((item == nullptr) || item->getId() == 0)
376  continue;
377 
378  Image *const image = item->getImage();
379  if (image != nullptr)
380  {
381  if (mShowMatrix[itemIndex] == mSelectedIndex)
382  {
383  if (mSelImg != nullptr)
384  graphics->drawImage(mSelImg, itemX, itemY);
385  }
386  image->setAlpha(1.0F); // ensure the image if fully drawn...
387  graphics->drawImage(image,
388  itemX + mPaddingItemX,
389  itemY + mPaddingItemY);
390  if ((mProtectedImg != nullptr) && PlayerInfo::isItemProtected(
391  item->getId()))
392  {
393  graphics->drawImage(mProtectedImg,
394  itemX + mPaddingItemX,
395  itemY + mPaddingItemY);
396  }
397  }
398  }
399  }
400 
401  for (int j = 0; j < mDrawRows; j++)
402  {
403  const int intY0 = j * mBoxHeight;
404  int itemIndex = j * mGridColumns - 1;
405  for (int i = 0; i < mGridColumns; i++)
406  {
407  int itemX = i * mBoxWidth;
408  int itemY = intY0;
409  itemIndex ++;
410  if (mShowMatrix[itemIndex] < 0)
411  continue;
412 
413  const Item *const item = mInventory->getItem(
414  mShowMatrix[itemIndex]);
415 
416  if ((item == nullptr) || item->getId() == 0)
417  continue;
418 
419  // Draw item caption
420  std::string caption;
421  if (item->getQuantity() > 1 ||
423  {
424  caption = toString(item->getQuantity());
425  }
426  else if (item->isEquipped() == Equipped_true)
427  {
428  // TRANSLATORS: Text under equipped items (should be small)
429  caption = _("Eq.");
430  }
431 
432  if (item->isEquipped() == Equipped_true)
433  {
434  font->drawString(graphics,
436  caption,
437  itemX + (mBoxWidth - font->getWidth(caption)) / 2,
438  itemY + mEquippedTextPadding);
439  }
440  else
441  {
442  font->drawString(graphics,
444  caption,
445  itemX + (mBoxWidth - font->getWidth(caption)) / 2,
446  itemY + mEquippedTextPadding);
447  }
448  }
449  }
450  BLOCK_END("ItemContainer::draw")
451 }
452 
453 void ItemContainer::safeDraw(Graphics *const graphics)
454 {
455  if ((mInventory == nullptr) || (mShowMatrix == nullptr))
456  return;
457 
458  BLOCK_START("ItemContainer::draw")
459  Font *const font = getFont();
460 
461  if (mCellBackgroundImg != nullptr)
462  {
463  const int invSize = mInventory->getSize();
464  const int maxRows = mShowEmptyRows == ShowEmptyRows_true ?
465  std::max(invSize / mGridColumns, mGridRows) : mGridRows;
466  const int maxColumns = mGridColumns > invSize ?
467  invSize : mGridColumns;
468  for (int j = 0; j < maxRows; j++)
469  {
470  const int intY0 = j * mBoxHeight;
471  for (int i = 0; i < maxColumns; i++)
472  {
473  int itemX = i * mBoxWidth;
474  int itemY = intY0;
475  graphics->drawImage(mCellBackgroundImg,
476  itemX + mPaddingItemX,
477  itemY + mPaddingItemY);
478  }
479  }
480  }
481 
482  for (int j = 0; j < mDrawRows; j++)
483  {
484  const int intY0 = j * mBoxHeight;
485  int itemIndex = j * mGridColumns - 1;
486  for (int i = 0; i < mGridColumns; i++)
487  {
488  int itemX = i * mBoxWidth;
489  int itemY = intY0;
490  itemIndex ++;
491  if (mShowMatrix[itemIndex] < 0)
492  continue;
493 
494  const Item *const item = mInventory->getItem(
495  mShowMatrix[itemIndex]);
496 
497  if ((item == nullptr) || item->getId() == 0)
498  continue;
499 
500  Image *const image = item->getImage();
501  if (image != nullptr)
502  {
503  if (mShowMatrix[itemIndex] == mSelectedIndex)
504  {
505  if (mSelImg != nullptr)
506  graphics->drawImage(mSelImg, itemX, itemY);
507  }
508  image->setAlpha(1.0F); // ensure the image if fully drawn...
509  graphics->drawImage(image,
510  itemX + mPaddingItemX,
511  itemY + mPaddingItemY);
512  if ((mProtectedImg != nullptr) && PlayerInfo::isItemProtected(
513  item->getId()))
514  {
515  graphics->drawImage(mProtectedImg,
516  itemX + mPaddingItemX,
517  itemY + mPaddingItemY);
518  }
519  }
520  }
521  }
522 
523  for (int j = 0; j < mDrawRows; j++)
524  {
525  const int intY0 = j * mBoxHeight;
526  int itemIndex = j * mGridColumns - 1;
527  for (int i = 0; i < mGridColumns; i++)
528  {
529  int itemX = i * mBoxWidth;
530  int itemY = intY0;
531  itemIndex ++;
532  if (mShowMatrix[itemIndex] < 0)
533  continue;
534 
535  const Item *const item = mInventory->getItem(
536  mShowMatrix[itemIndex]);
537 
538  if ((item == nullptr) || item->getId() == 0)
539  continue;
540 
541  // Draw item caption
542  std::string caption;
543  if (item->getQuantity() > 1 ||
545  {
546  caption = toString(item->getQuantity());
547  }
548  else if (item->isEquipped() == Equipped_true)
549  {
550  // TRANSLATORS: Text under equipped items (should be small)
551  caption = _("Eq.");
552  }
553 
554  if (item->isEquipped() == Equipped_true)
555  {
556  font->drawString(graphics,
558  caption,
559  itemX + (mBoxWidth - font->getWidth(caption)) / 2,
560  itemY + mEquippedTextPadding);
561  }
562  else
563  {
564  font->drawString(graphics,
566  caption,
567  itemX + (mBoxWidth - font->getWidth(caption)) / 2,
568  itemY + mEquippedTextPadding);
569  }
570  }
571  }
572  BLOCK_END("ItemContainer::draw")
573 }
574 
576 {
577  dragDrop.clear();
578 
579  setSelectedIndex(-1);
581 /*
582  if (outfitWindow)
583  outfitWindow->setItemSelected(-1);
584  if (shopWindow)
585  shopWindow->setItemSelected(-1);
586 */
587 }
588 
589 void ItemContainer::setSelectedIndex(const int newIndex)
590 {
591  if (mSelectedIndex != newIndex)
592  {
593  mSelectedIndex = newIndex;
595  }
596 }
597 
599 {
600  if (mInventory != nullptr)
602  return nullptr;
603 }
604 
606 {
608  {
609  if (*i != nullptr)
610  {
611  SelectionEvent event(this);
612  (*i)->valueChanged(event);
613  }
614  }
615 }
616 
618 {
619 }
620 
622 {
623 }
624 
626 {
627  if (mInventory == nullptr)
628  return;
629 
630  const MouseButtonT button = event.getButton();
631  mClicks = event.getClickCount();
632 
633  if (button == MouseButton::LEFT || button == MouseButton::RIGHT)
634  {
635  event.consume();
636  const int index = getSlotIndex(event.getX(), event.getY());
637  if (index == Inventory::NO_SLOT_INDEX)
638  return;
639 
640  Item *const item = mInventory->getItem(index);
641 
642  // put item name into chat window
643  if ((item != nullptr) && mDescItems && (chatWindow != nullptr))
645 
647  switch (mInventory->getType())
648  {
651  break;
654  break;
656  src = DragDropSource::Trade;
657  break;
658  case InventoryType::Npc:
659  src = DragDropSource::Npc;
660  break;
661  case InventoryType::Cart:
662  src = DragDropSource::Cart;
663  break;
666  break;
669  break;
671  src = DragDropSource::Craft;
672  break;
673  default:
676  break;
677  }
678  if (src == DragDropSource::MailView)
679  return;
680  if (mSelectedIndex == index && mClicks != 2)
681  {
682  dragDrop.dragItem(item, src, index);
683  dragDrop.select(item);
685  }
686  else if ((item != nullptr) && (item->getId() != 0))
687  {
688  if (index >= 0)
689  {
690  dragDrop.dragItem(item, src, index);
691  dragDrop.select(item);
692  setSelectedIndex(index);
694 
695  if (itemShortcutWindow != nullptr)
696  {
697  const int num = itemShortcutWindow->getTabIndex();
698  if (num >= 0 && num < CAST_S32(SHORTCUT_TABS))
699  {
700  if (itemShortcut[num] != nullptr)
701  itemShortcut[num]->setItemSelected(item);
702  }
703  }
704  if (shopWindow != nullptr)
705  shopWindow->setItemSelected(item->getId());
706  }
707  }
708  else
709  {
710  dragDrop.deselect();
711  selectNone();
712  }
713  }
714 }
715 
717 {
718  if (mSelectionStatus != SEL_NONE)
720 }
721 
723 {
724  if (mClicks == 2 ||
725  inventoryHandler == nullptr ||
726  tradeHandler == nullptr)
727  {
728  return;
729  }
730 
731  switch (mSelectionStatus)
732  {
733  case SEL_SELECTING:
735  break;
736  case SEL_DESELECTING:
737  selectNone();
738  break;
739  case SEL_DRAGGING:
741  break;
742  case SEL_NONE:
743  case SEL_SELECTED:
744  default:
745  break;
746  };
747 
748  if (dragDrop.isEmpty())
749  {
750  const int index = getSlotIndex(event.getX(), event.getY());
751  if (index == Inventory::NO_SLOT_INDEX)
752  return;
753  if (index == mSelectedIndex || mSelectedIndex == -1)
754  return;
756  selectNone();
757  }
758  else if (mInventory != nullptr)
759  {
760  const DragDropSourceT src = dragDrop.getSource();
762  switch (mInventory->getType())
763  {
766  break;
769  break;
771  dst = DragDropSource::Trade;
772  break;
773  case InventoryType::Npc:
774  dst = DragDropSource::Npc;
775  break;
778  break;
781  break;
782  case InventoryType::Cart:
783  dst = DragDropSource::Cart;
784  break;
786  dst = DragDropSource::Craft;
787  break;
788  default:
791  break;
792  }
793  InventoryTypeT srcContainer = InventoryType::TypeEnd;
794  InventoryTypeT dstContainer = InventoryType::TypeEnd;
795  bool checkProtection(false);
796  Inventory *inventory = nullptr;
797  if (src == DragDropSource::Inventory
798  && dst == DragDropSource::Storage)
799  {
800  srcContainer = InventoryType::Inventory;
801  dstContainer = InventoryType::Storage;
802  inventory = PlayerInfo::getInventory();
803  }
804  else if (src == DragDropSource::Storage
805  && dst == DragDropSource::Inventory)
806  {
807  srcContainer = InventoryType::Storage;
808  dstContainer = InventoryType::Inventory;
809  inventory = PlayerInfo::getStorageInventory();
810  }
811  if (src == DragDropSource::Inventory
812  && dst == DragDropSource::Cart)
813  {
814  srcContainer = InventoryType::Inventory;
815  dstContainer = InventoryType::Cart;
816  inventory = PlayerInfo::getInventory();
817  }
818  if (src == DragDropSource::Inventory
819  && dst == DragDropSource::Inventory)
820  {
822  return;
823  const int index = getSlotIndex(event.getX(), event.getY());
824  if (index == Inventory::NO_SLOT_INDEX)
825  return;
826  if (index == mSelectedIndex || mSelectedIndex == -1)
827  return;
828  if (inventoryWindow != nullptr)
830  return;
831  }
832  else if (src == DragDropSource::Cart
833  && dst == DragDropSource::Inventory)
834  {
835  srcContainer = InventoryType::Cart;
836  dstContainer = InventoryType::Inventory;
837  inventory = PlayerInfo::getCartInventory();
838  }
839  else if (src == DragDropSource::Cart
840  && dst == DragDropSource::Storage)
841  {
842  srcContainer = InventoryType::Cart;
843  dstContainer = InventoryType::Storage;
844  inventory = PlayerInfo::getCartInventory();
845  }
846  else if (src == DragDropSource::Storage
847  && dst == DragDropSource::Cart)
848  {
849  srcContainer = InventoryType::Storage;
850  dstContainer = InventoryType::Cart;
851  inventory = PlayerInfo::getStorageInventory();
852  }
853  if (src == DragDropSource::Inventory
854  && dst == DragDropSource::Trade)
855  {
856  checkProtection = true;
857  inventory = PlayerInfo::getInventory();
858  }
859  else if (src == DragDropSource::Inventory &&
860  dst == DragDropSource::Npc)
861  {
862  inventory = PlayerInfo::getInventory();
863  if (inventory != nullptr)
864  {
865  Item *const item = inventory->getItem(dragDrop.getTag());
867  item,
868  getSlotByXY(event.getX(), event.getY()),
869  1))
870  {
871  inventory->virtualRemove(item, 1);
872  }
873  }
874  return;
875  }
876  else if (src == DragDropSource::Inventory &&
878  {
879  inventory = PlayerInfo::getInventory();
880  if (inventory == nullptr)
881  return;
882  Item *const item = inventory->getItem(dragDrop.getTag());
883  if (item == nullptr)
884  return;
886  {
887  if (item->getQuantity() > 1
889  {
893  item);
894  }
895  else
896  {
897  mail2Handler->addItem(item, 1);
898  }
899  }
900  else
901  {
903  item,
904  getSlotByXY(event.getX(), event.getY()),
905  1))
906  {
907  inventory->virtualRemove(item, 1);
908  }
909  }
910  return;
911  }
912  else if (src == DragDropSource::Npc)
913  {
914  inventory = PlayerInfo::getInventory();
915  if (dst == DragDropSource::Npc)
916  {
917  const Item *const item = mInventory->getItem(
918  dragDrop.getTag());
919  const int index = getSlotByXY(event.getX(), event.getY());
920  if (index == Inventory::NO_SLOT_INDEX)
921  {
922  if (inventory != nullptr)
923  inventory->virtualRestore(item, 1);
925  return;
926  }
927  mInventory->removeItemAt(index);
928  mInventory->setItem(index,
929  item->getId(),
930  item->getType(),
931  1,
932  1,
933  item->getColor(),
934  item->getIdentified(),
935  item->getDamaged(),
936  item->getFavorite(),
937  Equipm_false,
939  Item *const item2 = mInventory->getItem(index);
940  if (item2 != nullptr)
941  item2->setTag(item->getTag());
943  }
944  else
945  {
946  if (inventory != nullptr)
947  {
948  const Item *const item = inventory->getItem(
949  dragDrop.getTag());
950  if (item != nullptr)
951  {
952  inventory->virtualRestore(item, 1);
954  }
955  }
956  return;
957  }
958  }
959  else if (src == DragDropSource::Inventory &&
960  dst == DragDropSource::Craft)
961  {
962  inventory = PlayerInfo::getInventory();
963  if (inventory != nullptr)
964  {
965  Item *const item = inventory->getItem(dragDrop.getTag());
966  if ((item == nullptr) || item->isEquipped() == Equipped_true)
967  return;
968  const int slot = getSlotByXY(event.getX(), event.getY());
969  if (item->getQuantity() > 1
971  {
975  item,
976  0,
977  slot);
978  }
979  else
980  {
982  item,
983  slot,
984  1))
985  {
986  inventory->virtualRemove(item, 1);
987  }
988  }
989  }
990  return;
991  }
992  else if (src == DragDropSource::Craft)
993  {
994  inventory = PlayerInfo::getInventory();
995  if (dst == DragDropSource::Craft)
996  {
997  const Item *const item = mInventory->getItem(
998  dragDrop.getTag());
999  const int index = getSlotByXY(event.getX(), event.getY());
1000  if (index == Inventory::NO_SLOT_INDEX)
1001  {
1002  if (inventory != nullptr)
1003  {
1004  inventory->virtualRestore(item,
1005  item->getQuantity());
1007  }
1008  return;
1009  }
1010  mInventory->moveItem(index, dragDrop.getTag());
1011  }
1012  else
1013  {
1014  if (inventory != nullptr)
1015  {
1016  const Item *const item = inventory->getItem(
1017  dragDrop.getTag());
1018  if (item != nullptr)
1019  {
1020  inventory->virtualRestore(item,
1021  item->getQuantity());
1023  }
1024  }
1025  return;
1026  }
1027  }
1028  else if (src == DragDropSource::MailEdit)
1029  {
1030  if (event.getType() == MouseEventType::RELEASED2)
1031  return;
1033  {
1034  if (mailEditWindow == nullptr)
1035  return;
1036  inventory = mailEditWindow->getInventory();
1037  if (inventory == nullptr)
1038  return;
1039  const Item *const item = inventory->getItem(dragDrop.getTag());
1040  if (item == nullptr)
1041  return;
1042  mail2Handler->removeItem(item->getTag(),
1043  item->getQuantity());
1044  }
1045  else
1046  {
1047  inventory = PlayerInfo::getInventory();
1048  if (inventory == nullptr)
1049  return;
1050  const Item *const item = inventory->getItem(dragDrop.getTag());
1051  if (item == nullptr)
1052  return;
1054  }
1055  return;
1056  }
1057 
1058  if (inventory != nullptr)
1059  {
1060  const Item *const item = inventory->getItem(dragDrop.getTag());
1061  if (item != nullptr)
1062  {
1063  if (srcContainer != InventoryType::TypeEnd)
1064  { // inventory <--> storage, cart
1065  inventoryHandler->moveItem2(srcContainer,
1066  item->getInvIndex(),
1067  item->getQuantity(),
1068  dstContainer);
1069  }
1070  else
1071  { // inventory --> trade
1072  if (!checkProtection || !PlayerInfo::isItemProtected(
1073  item->getId()))
1074  {
1075  tradeHandler->addItem(item, item->getQuantity());
1076  }
1077  }
1078  }
1079  }
1080  }
1081 }
1082 
1084 {
1085  if (mInventory == nullptr)
1086  return;
1087 
1088  const Item *const item = mInventory->getItem(
1089  getSlotIndex(event.getX(), event.getY()));
1090 
1091  if ((item != nullptr) && (viewport != nullptr))
1092  {
1093  itemPopup->setItem(item, false);
1095  }
1096  else
1097  {
1099  }
1100 }
1101 
1103 {
1105 }
1106 
1108 {
1109  updateSize();
1110 }
1111 
1113 {
1114  mGridColumns = std::min(mMaxColumns,
1115  std::max(1, mDimension.width / mBoxWidth));
1116  if (mGridColumns > mMaxColumns)
1118  adjustHeight();
1119  mRedraw = true;
1120 }
1121 
1123 {
1124  mRedraw = true;
1125 }
1126 
1128 {
1129  if (mGridColumns == 0)
1130  return;
1131 
1133  if (mGridRows == 0 || (mLastUsedSlot + 1) % mGridColumns > 0)
1134  ++mGridRows;
1135 
1136  const int invSize = mInventory->getSize();
1137  int maxRows = mShowEmptyRows == ShowEmptyRows_true ?
1138  std::max(invSize / mGridColumns, mGridRows) : mGridRows;
1139 
1141  {
1142  if (mGridColumns * maxRows < invSize)
1143  maxRows ++;
1144  mGridRows = maxRows;
1145  }
1146 
1147  const int num = updateMatrix();
1149  {
1150  mDrawRows = num / mGridColumns;
1151  if (mDrawRows == 0 || num % mGridColumns > 0)
1152  ++mDrawRows;
1153 
1154  maxRows = mDrawRows;
1155  }
1156  else
1157  {
1158  mDrawRows = mGridRows;
1159  }
1160  setHeight(maxRows * mBoxHeight);
1161 }
1162 
1164 {
1165  if (mInventory == nullptr)
1166  return 0;
1167 
1168  mRedraw = true;
1169  delete []mShowMatrix;
1171 
1172  STD_VECTOR<ItemIdPair*> sortedItems;
1173  int i = 0;
1174  int j = 0;
1175 
1176  std::string temp = mName;
1177  toLower(temp);
1178 
1179  const unsigned int invSize = mInventory->getSize();
1180  for (unsigned int idx = 0; idx < invSize; idx ++)
1181  {
1182  Item *const item = mInventory->getItem(idx);
1183 
1184  if (item == nullptr ||
1185  item->getId() == 0 ||
1186  !item->isHaveTag(mTag) ||
1187  item->getQuantity() == 0)
1188  {
1190  sortedItems.push_back(new ItemIdPair(idx, nullptr));
1191  continue;
1192  }
1193 
1194  if (!item->isHaveTag(mTag))
1195  continue;
1196 
1197  if (mName.empty())
1198  {
1199  sortedItems.push_back(new ItemIdPair(idx, item));
1200  continue;
1201  }
1202  std::string name = item->getInfo().getName();
1203  toLower(name);
1204  if (name.find(temp) != std::string::npos)
1205  sortedItems.push_back(new ItemIdPair(idx, item));
1206  }
1207 
1208  switch (mSortType)
1209  {
1210  case 0:
1211  default:
1212  break;
1213  case 1:
1214  std::sort(sortedItems.begin(), sortedItems.end(),
1216  break;
1217  case 2:
1218  std::sort(sortedItems.begin(), sortedItems.end(), itemIdInvSorter);
1219  break;
1220  case 3:
1221  std::sort(sortedItems.begin(), sortedItems.end(),
1223  break;
1224  case 4:
1225  std::sort(sortedItems.begin(), sortedItems.end(),
1227  break;
1228  case 5:
1229  std::sort(sortedItems.begin(), sortedItems.end(),
1231  break;
1232  }
1233 
1234  int jMult = j * mGridColumns;
1235  const int maxSize = mGridRows * mGridColumns;
1236  FOR_EACH (STD_VECTOR<ItemIdPair*>::const_iterator, iter, sortedItems)
1237  {
1238  if (jMult >= maxSize)
1239  break;
1240 
1241  mShowMatrix[jMult + i] = (*iter)->mId;
1242 
1243  i ++;
1244  if (i >= mGridColumns)
1245  {
1246  i = 0;
1247  j ++;
1248  jMult += mGridColumns;
1249  }
1250  }
1251 
1252  for (int idx = j * mGridColumns + i; idx < maxSize; idx ++)
1253  mShowMatrix[idx] = -1;
1254 
1255  const int num = CAST_S32(sortedItems.size());
1256  for (size_t idx = 0, sz = num; idx < sz; idx ++)
1257  delete sortedItems[idx];
1258  return num;
1259 }
1260 
1261 int ItemContainer::getSlotIndex(int x, int y) const
1262 {
1263  if (mShowMatrix == nullptr)
1264  return Inventory::NO_SLOT_INDEX;
1265 
1266  if (x < mDimension.width && y < mDimension.height && x >= 0 && y >= 0)
1267  {
1268  if (x > mBoxWidth * mGridColumns)
1269  return Inventory::NO_SLOT_INDEX;
1270  const int idx = (y / mBoxHeight) * mGridColumns + (x / mBoxWidth);
1271  if (idx >= 0 && idx < mGridRows * mGridColumns
1272  && mShowMatrix[idx] >= 0)
1273  {
1274  return mShowMatrix[idx];
1275  }
1276  }
1277 
1278  return Inventory::NO_SLOT_INDEX;
1279 }
1280 
1281 int ItemContainer::getSlotByXY(int x, int y) const
1282 {
1283  if (mShowMatrix == nullptr)
1284  return Inventory::NO_SLOT_INDEX;
1285 
1286  if (x < mDimension.width && y < mDimension.height && x >= 0 && y >= 0)
1287  {
1288  if (x > mBoxWidth * mGridColumns)
1289  return Inventory::NO_SLOT_INDEX;
1290  const int idx = (y / mBoxHeight) * mGridColumns + (x / mBoxWidth);
1291  if (idx >= 0 && idx < mGridRows * mGridColumns)
1292  return idx;
1293  }
1294 
1295  return Inventory::NO_SLOT_INDEX;
1296 }
1297 
1298 void ItemContainer::setFilter(const int tag)
1299 {
1300  mTag = tag;
1301  adjustHeight();
1302 }
1303 
1304 void ItemContainer::setSortType(const int sortType)
1305 {
1306  mSortType = sortType;
1307  updateMatrix();
1308 }
1309 
1310 void ItemContainer::setCellBackgroundImage(const std::string &xmlName)
1311 {
1312  if (mCellBackgroundImg != nullptr)
1315  mRedraw = true;
1316 }
1317 
1318 void ItemContainer::setMaxColumns(const int maxColumns)
1319 {
1320  mMaxColumns = maxColumns;
1321  updateSize();
1322 }
#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:88
#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
void dragItem(const Item *const item, const DragDropSourceT source, const int tag=0)
Definition: dragdrop.h:86
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)
void keyReleased(KeyEvent &event) A_CONST
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:1129
void widgetMoved(const Event &event)
Inventory * getInventory()
Definition: playerinfo.cpp:207
#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
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
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:104
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
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:285
void setCellBackgroundImage(const std::string &xmlName)
Inventory * getCartInventory()
Definition: playerinfo.cpp:219
#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
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:229
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 keyPressed(KeyEvent &event) A_CONST
void mouseExited(MouseEvent &event)
Definition: item.h:48
std::string toLower(std::string const &s)
Inventory * getStorageInventory()
Definition: playerinfo.cpp:212
#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:183
bool getRedraw() const
Definition: graphics.h:286
Color mUnEquipedColor
ShowEmptyRows mShowEmptyRows
ItemShortcut * itemShortcut[SHORTCUT_TABS]
Net::InventoryHandler * inventoryHandler
Definition: net.cpp:82
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
static void showWindow(const ItemAmountWindowUsageT usage, Window *const parent, Item *const item, int maxRange=0, const int tag=0)
ShopWindow * shopWindow
Definition: shopwindow.cpp:97
ServerTypeT getNetworkType()
Definition: net.cpp:178
MouseEventTypeT getType() const
Definition: mouseevent.h:152
bool isItemProtected(const int id)
Definition: playerinfo.cpp:526
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:171
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:1144
Definition: widget.h:97
void setSelectedIndex(const int index)
Net::TradeHandler * tradeHandler
Definition: net.cpp:91
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:86
#define CAST_SIZE
Definition: cast.h:33
int getX() const
Definition: mouseevent.h:124
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
ItemContainer(const Widget2 *const widget, Inventory *const inventory, const int maxColumns=100000, const ShowEmptyRows showEmptyRows=ShowEmptyRows_false, const ForceQuantity forceQuantity=ForceQuantity_false)
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:163
const bool ForceQuantity_true
Definition: forcequantity.h:29
void decRef()
Definition: image.cpp:521
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