diff options
Diffstat (limited to 'src/gui/emotepopup.cpp')
-rw-r--r-- | src/gui/emotepopup.cpp | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/src/gui/emotepopup.cpp b/src/gui/emotepopup.cpp new file mode 100644 index 000000000..2a0d94aca --- /dev/null +++ b/src/gui/emotepopup.cpp @@ -0,0 +1,214 @@ +/* + * Extended support for activating emotes + * Copyright (C) 2009 Aethyra Development Team + * Copyright (C) 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/emotepopup.h" + +#include "animatedsprite.h" +#include "configuration.h" +#include "emoteshortcut.h" +#include "graphics.h" +#include "localplayer.h" +#include "log.h" + +#include "gui/theme.h" + +#include "resources/emotedb.h" +#include "resources/image.h" +#include "resources/iteminfo.h" + +#include "utils/dtor.h" + +#include <guichan/mouseinput.hpp> +#include <guichan/selectionlistener.hpp> + +const int EmotePopup::gridWidth = 34; // emote icon width + 4 +const int EmotePopup::gridHeight = 36; // emote icon height + 4 + +static const int MAX_COLUMNS = 6; + +EmotePopup::EmotePopup(): + mSelectedEmoteIndex(-1), + mHoveredEmoteIndex(-1), + mRowCount(1), + mColumnCount(1) +{ + // Setup emote sprites + for (int i = 0; i <= EmoteDB::getLast(); ++i) + { + const AnimatedSprite *sprite = EmoteDB::getAnimation(i, true); + if (sprite) + mEmotes.push_back(sprite); + } + + mSelectionImage = Theme::getImageFromTheme("selection.png"); + if (!mSelectionImage) + logger->log1("Error: Unable to load selection.png"); + + if (mSelectionImage) + mSelectionImage->setAlpha(Client::getGuiAlpha()); + + addMouseListener(this); + recalculateSize(); + setVisible(true); +} + +EmotePopup::~EmotePopup() +{ + if (mSelectionImage) + mSelectionImage->decRef(); +} + +void EmotePopup::draw(gcn::Graphics *graphics) +{ + Popup::draw(graphics); + + if (!mColumnCount) + return; + + const unsigned int emoteCount = static_cast<unsigned>(mEmotes.size()); + const unsigned int emotesLeft + = static_cast<unsigned>(mEmotes.size() % mColumnCount); + + for (unsigned int i = 0; i < emoteCount ; i++) + { + int row = i / mColumnCount; + int column = i % mColumnCount; + + unsigned int emoteX = 4 + column * gridWidth; + unsigned int emoteY = 4 + row * gridHeight; + + // Center the last row when there are less emotes than columns + if (emotesLeft > 0 && row == mRowCount - 1) + emoteX += (mColumnCount - emotesLeft) * gridWidth / 2; + + // Draw selection image below hovered item + if (mSelectionImage && static_cast<int>(i) == mHoveredEmoteIndex) + { + static_cast<Graphics*>(graphics)->drawImage( + mSelectionImage, emoteX, emoteY + 4); + } + + // Draw emote icon + if (mEmotes[i]) + mEmotes[i]->draw(static_cast<Graphics*>(graphics), emoteX, emoteY); + } +} + +void EmotePopup::mousePressed(gcn::MouseEvent &event) +{ + if (event.getButton() != gcn::MouseEvent::LEFT) + return; + + const int index = getIndexAt(event.getX(), event.getY()); + if (index != -1) + { + setSelectedEmoteIndex(index); + if (emoteShortcut) + { + emoteShortcut->setEmoteSelected( + static_cast<unsigned char>(index + 1)); + } + } +} + +void EmotePopup::mouseMoved(gcn::MouseEvent &event) +{ + Popup::mouseMoved(event); + + mHoveredEmoteIndex = getIndexAt(event.getX(), event.getY()); +} + +int EmotePopup::getSelectedEmote() const +{ + return 1 + mSelectedEmoteIndex; +} + +void EmotePopup::setSelectedEmoteIndex(int index) +{ + if (index == mSelectedEmoteIndex) + return; + + mSelectedEmoteIndex = index; + distributeValueChangedEvent(); +} + +int EmotePopup::getIndexAt(int x, int y) const +{ + if (!gridWidth || !gridHeight) + return -1; + + const unsigned int emotesLeft + = static_cast<unsigned>(mEmotes.size() % mColumnCount); + const unsigned int row = y / gridHeight; + unsigned int column; + + // Take into account that the last row is centered + if (emotesLeft > 0 && static_cast<signed>(row) == mRowCount - 1) + { + int unsigned emotesMissing = mColumnCount - emotesLeft; + column = std::min((x - emotesMissing * gridWidth / 2) / gridWidth, + emotesLeft - 1); + } + else + { + column = std::min(x / gridWidth, mColumnCount - 1); + } + + int unsigned index = column + (row * mColumnCount); + + if (index < mEmotes.size()) + return index; + + return -1; +} + +void EmotePopup::recalculateSize() +{ + const unsigned emoteCount = static_cast<unsigned>(mEmotes.size()); + + mRowCount = emoteCount / MAX_COLUMNS; + if (emoteCount % MAX_COLUMNS > 0) + ++mRowCount; + + if (mRowCount) + mColumnCount = emoteCount / mRowCount; + else + mColumnCount = 1; + + if (emoteCount % mRowCount > 0) + ++mColumnCount; + + setContentSize(mColumnCount * gridWidth, mRowCount * gridHeight); +} + +void EmotePopup::distributeValueChangedEvent() +{ + gcn::SelectionEvent event(this); + Listeners::const_iterator i_end = mListeners.end(); + Listeners::const_iterator i; + + for (i = mListeners.begin(); i != i_end; ++i) + { + if (*i) + (*i)->valueChanged(event); + } +} |