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