summaryrefslogtreecommitdiff
path: root/src/gui/widgets/itemcontainer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/widgets/itemcontainer.cpp')
-rw-r--r--src/gui/widgets/itemcontainer.cpp475
1 files changed, 475 insertions, 0 deletions
diff --git a/src/gui/widgets/itemcontainer.cpp b/src/gui/widgets/itemcontainer.cpp
new file mode 100644
index 000000000..8b5b1914a
--- /dev/null
+++ b/src/gui/widgets/itemcontainer.cpp
@@ -0,0 +1,475 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gui/widgets/itemcontainer.h"
+
+#include "graphics.h"
+#include "inventory.h"
+#include "item.h"
+#include "itemshortcut.h"
+#include "dropshortcut.h"
+#include "log.h"
+
+#include "gui/chat.h"
+#include "gui/itempopup.h"
+#include "gui/outfitwindow.h"
+#include "gui/palette.h"
+#include "gui/shopwindow.h"
+#include "gui/shortcutwindow.h"
+#include "gui/sdlinput.h"
+#include "gui/theme.h"
+#include "gui/viewport.h"
+
+#include "net/net.h"
+#include "net/inventoryhandler.h"
+
+#include "resources/image.h"
+#include "resources/iteminfo.h"
+
+#include "utils/stringutils.h"
+
+#include <guichan/mouseinput.hpp>
+#include <guichan/selectionlistener.hpp>
+
+// TODO: Add support for adding items to the item shortcut window (global
+// itemShortcut).
+
+static const int BOX_WIDTH = 35;
+static const int BOX_HEIGHT = 43;
+
+ItemContainer::ItemContainer(Inventory *inventory, bool forceQuantity):
+ mInventory(inventory),
+ mGridColumns(1),
+ mGridRows(1),
+ mSelectedIndex(-1),
+ mHighlightedIndex(-1),
+ mLastUsedSlot(-1),
+ mSelectionStatus(SEL_NONE),
+ mForceQuantity(forceQuantity),
+ mSwapItems(false),
+ mDescItems(false)
+{
+ mItemPopup = new ItemPopup;
+ setFocusable(true);
+
+ mSelImg = Theme::getImageFromTheme("selection.png");
+ if (!mSelImg)
+ logger->log1("Error: Unable to load selection.png");
+
+ addKeyListener(this);
+ addMouseListener(this);
+ addWidgetListener(this);
+}
+
+ItemContainer::~ItemContainer()
+{
+ if (mSelImg)
+ {
+ mSelImg->decRef();
+ mSelImg = 0;
+ }
+ delete mItemPopup;
+ mItemPopup = 0;
+}
+
+void ItemContainer::logic()
+{
+ gcn::Widget::logic();
+
+ if (!mInventory)
+ return;
+
+ const int lastUsedSlot = mInventory->getLastUsedSlot();
+
+ if (lastUsedSlot != mLastUsedSlot)
+ {
+ mLastUsedSlot = lastUsedSlot;
+ adjustHeight();
+ }
+}
+
+void ItemContainer::draw(gcn::Graphics *graphics)
+{
+ if (!mInventory)
+ return;
+
+ Graphics *g = static_cast<Graphics*>(graphics);
+
+ g->setFont(getFont());
+
+ for (int i = 0; i < mGridColumns; i++)
+ {
+ for (int j = 0; j < mGridRows; j++)
+ {
+ int itemX = i * BOX_WIDTH;
+ int itemY = j * BOX_HEIGHT;
+ int itemIndex = (j * mGridColumns) + i;
+ Item *item = mInventory->getItem(itemIndex);
+
+ if (!item || item->getId() == 0)
+ continue;
+
+ Image *image = item->getImage();
+ if (image)
+ {
+ if (itemIndex == mSelectedIndex)
+ {
+ if (mSelectionStatus == SEL_DRAGGING)
+ {
+ // Reposition the coords to that of the cursor.
+ itemX = mDragPosX - (BOX_WIDTH / 2);
+ itemY = mDragPosY - (BOX_HEIGHT / 2);
+ }
+ else
+ {
+ // Draw selection border image.
+ if (mSelImg)
+ g->drawImage(mSelImg, itemX, itemY);
+ }
+ }
+ image->setAlpha(1.0f); // ensure the image if fully drawn...
+ g->drawImage(image, itemX, itemY);
+ }
+ // Draw item caption
+ std::string caption;
+ if (item->getQuantity() > 1 || mForceQuantity)
+ caption = toString(item->getQuantity());
+ else if (item->isEquipped())
+ caption = "Eq.";
+
+ if (item->isEquipped())
+ g->setColor(Theme::getThemeColor(Theme::ITEM_EQUIPPED));
+ else
+ g->setColor(gcn::Color(0, 0, 0));
+
+ g->drawText(caption, itemX + BOX_WIDTH / 2,
+ itemY + BOX_HEIGHT - 14, gcn::Graphics::CENTER);
+ }
+ }
+
+ // Draw an orange box around the selected item
+ if (isFocused() && mHighlightedIndex != -1 && mGridColumns)
+ {
+ const int itemX = (mHighlightedIndex % mGridColumns) * BOX_WIDTH;
+ const int itemY = (mHighlightedIndex / mGridColumns) * BOX_HEIGHT;
+ g->setColor(gcn::Color(255, 128, 0));
+ g->drawRectangle(gcn::Rectangle(itemX, itemY, BOX_WIDTH, BOX_HEIGHT));
+ }
+}
+
+void ItemContainer::selectNone()
+{
+ setSelectedIndex(-1);
+ mSelectionStatus = SEL_NONE;
+ if (outfitWindow)
+ outfitWindow->setItemSelected(-1);
+ if (shopWindow)
+ shopWindow->setItemSelected(-1);
+}
+
+void ItemContainer::setSelectedIndex(int newIndex)
+{
+ if (mSelectedIndex != newIndex)
+ {
+ mSelectedIndex = newIndex;
+ distributeValueChangedEvent();
+ }
+}
+
+Item *ItemContainer::getSelectedItem() const
+{
+ if (mInventory)
+ return mInventory->getItem(mSelectedIndex);
+ else
+ return 0;
+}
+
+void ItemContainer::distributeValueChangedEvent()
+{
+ SelectionListenerIterator i, i_end;
+
+ for (i = mSelectionListeners.begin(), i_end = mSelectionListeners.end();
+ i != i_end; ++i)
+ {
+ if (*i)
+ {
+ gcn::SelectionEvent event(this);
+ (*i)->valueChanged(event);
+ }
+ }
+}
+
+void ItemContainer::keyPressed(gcn::KeyEvent &event _UNUSED_)
+{
+ /*switch (event.getKey().getValue())
+ {
+ case Key::LEFT:
+ moveHighlight(Left);
+ break;
+ case Key::RIGHT:
+ moveHighlight(Right);
+ break;
+ case Key::UP:
+ moveHighlight(Up);
+ break;
+ case Key::DOWN:
+ moveHighlight(Down);
+ break;
+ case Key::SPACE:
+ keyAction();
+ break;
+ case Key::LEFT_ALT:
+ case Key::RIGHT_ALT:
+ mSwapItems = true;
+ break;
+ case Key::RIGHT_CONTROL:
+ mDescItems = true;
+ break;
+ }*/
+}
+
+void ItemContainer::keyReleased(gcn::KeyEvent &event _UNUSED_)
+{
+ /*switch (event.getKey().getValue())
+ {
+ case Key::LEFT_ALT:
+ case Key::RIGHT_ALT:
+ mSwapItems = false;
+ break;
+ case Key::RIGHT_CONTROL:
+ mDescItems = false;
+ break;
+ }*/
+}
+
+void ItemContainer::mousePressed(gcn::MouseEvent &event)
+{
+ if (!mInventory)
+ return;
+
+ const int button = event.getButton();
+ if (button == gcn::MouseEvent::LEFT || button == gcn::MouseEvent::RIGHT)
+ {
+ const int index = getSlotIndex(event.getX(), event.getY());
+ if (index == Inventory::NO_SLOT_INDEX)
+ return;
+
+ Item *item = mInventory->getItem(index);
+
+ // put item name into chat window
+ if (item && mDescItems && chatWindow)
+ chatWindow->addItemText(item->getInfo().getName());
+
+ if (mSelectedIndex == index)
+ {
+ mSelectionStatus = SEL_DESELECTING;
+ }
+ else if (item && item->getId())
+ {
+ setSelectedIndex(index);
+ mSelectionStatus = SEL_SELECTING;
+
+ int num = itemShortcutWindow->getTabIndex();
+ if (num >= 0 && num < SHORTCUT_TABS)
+ {
+ if (itemShortcut[num])
+ itemShortcut[num]->setItemSelected(item->getId());
+ }
+ if (dropShortcut)
+ dropShortcut->setItemSelected(item->getId());
+ if (item->isEquipment() && outfitWindow)
+ outfitWindow->setItemSelected(item->getId());
+ if (shopWindow)
+ shopWindow->setItemSelected(item->getId());
+ }
+ else
+ {
+ selectNone();
+ }
+ }
+}
+
+void ItemContainer::mouseDragged(gcn::MouseEvent &event)
+{
+ if (mSelectionStatus != SEL_NONE)
+ {
+ mSelectionStatus = SEL_DRAGGING;
+ mDragPosX = event.getX();
+ mDragPosY = event.getY();
+ }
+}
+
+void ItemContainer::mouseReleased(gcn::MouseEvent &event)
+{
+ switch (mSelectionStatus)
+ {
+ case SEL_SELECTING:
+ mSelectionStatus = SEL_SELECTED;
+ return;
+ case SEL_DESELECTING:
+ selectNone();
+ return;
+ case SEL_DRAGGING:
+ mSelectionStatus = SEL_SELECTED;
+ break;
+ default:
+ return;
+ };
+
+ int index = getSlotIndex(event.getX(), event.getY());
+ if (index == Inventory::NO_SLOT_INDEX)
+ return;
+ if (index == mSelectedIndex || mSelectedIndex == -1)
+ return;
+ Net::getInventoryHandler()->moveItem(mSelectedIndex, index);
+ selectNone();
+}
+
+
+// Show ItemTooltip
+void ItemContainer::mouseMoved(gcn::MouseEvent &event)
+{
+ if (!mInventory)
+ return;
+
+ Item *item = mInventory->getItem(getSlotIndex(event.getX(), event.getY()));
+
+ if (item && viewport)
+ {
+ mItemPopup->setItem(item);
+ mItemPopup->position(viewport->getMouseX(), viewport->getMouseY());
+ }
+ else
+ {
+ mItemPopup->setVisible(false);
+ }
+}
+
+// Hide ItemTooltip
+void ItemContainer::mouseExited(gcn::MouseEvent &event _UNUSED_)
+{
+ mItemPopup->setVisible(false);
+}
+
+void ItemContainer::widgetResized(const gcn::Event &event _UNUSED_)
+{
+ mGridColumns = std::max(1, getWidth() / BOX_WIDTH);
+ adjustHeight();
+}
+
+void ItemContainer::adjustHeight()
+{
+ if (!mGridColumns)
+ return;
+
+ mGridRows = (mLastUsedSlot + 1) / mGridColumns;
+ if (mGridRows == 0 || (mLastUsedSlot + 1) % mGridColumns > 0)
+ ++mGridRows;
+
+ setHeight(mGridRows * BOX_HEIGHT);
+}
+
+int ItemContainer::getSlotIndex(int x, int y) const
+{
+ if (x < getWidth() && y < getHeight())
+ return (y / BOX_HEIGHT) * mGridColumns + (x / BOX_WIDTH);
+
+ return Inventory::NO_SLOT_INDEX;
+}
+
+void ItemContainer::keyAction()
+{
+ // If there is no highlight then return.
+ if (mHighlightedIndex == -1)
+ return;
+
+ // If the highlight is on the selected item, then deselect it.
+ if (mHighlightedIndex == mSelectedIndex)
+ {
+ selectNone();
+ }
+ // Check and swap items if necessary.
+ else if (mSwapItems && mSelectedIndex != -1 && mHighlightedIndex != -1)
+ {
+ Net::getInventoryHandler()->moveItem(
+ mSelectedIndex, mHighlightedIndex);
+ setSelectedIndex(mHighlightedIndex);
+ }
+ // If the highlight is on an item then select it.
+ else if (mHighlightedIndex != -1)
+ {
+ setSelectedIndex(mHighlightedIndex);
+ mSelectionStatus = SEL_SELECTED;
+ }
+ // If the highlight is on a blank space then move it.
+ else if (mSelectedIndex != -1)
+ {
+ Net::getInventoryHandler()->moveItem(
+ mSelectedIndex, mHighlightedIndex);
+ selectNone();
+ }
+}
+
+void ItemContainer::moveHighlight(Direction direction)
+{
+ if (mHighlightedIndex == -1)
+ {
+ if (mSelectedIndex != -1)
+ mHighlightedIndex = mSelectedIndex;
+ else
+ mHighlightedIndex = 0;
+ return;
+ }
+
+ switch (direction)
+ {
+ case Left:
+ if (mHighlightedIndex % mGridColumns == 0)
+ mHighlightedIndex += mGridColumns;
+ mHighlightedIndex--;
+ break;
+ case Right:
+ if ((mHighlightedIndex % mGridColumns) ==
+ (mGridColumns - 1))
+ {
+ mHighlightedIndex -= mGridColumns;
+ }
+ mHighlightedIndex++;
+ break;
+ case Up:
+ if (mHighlightedIndex / mGridColumns == 0)
+ mHighlightedIndex += (mGridColumns * mGridRows);
+ mHighlightedIndex -= mGridColumns;
+ break;
+ case Down:
+ if ((mHighlightedIndex / mGridColumns) ==
+ (mGridRows - 1))
+ {
+ mHighlightedIndex -= (mGridColumns * mGridRows);
+ }
+ mHighlightedIndex += mGridColumns;
+ break;
+ default:
+ logger->log("warning moveHighlight unknown direction:"
+ + toString(static_cast<unsigned>(direction)));
+ break;
+ }
+}