diff options
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/commandhandler.cpp | 2 | ||||
-rw-r--r-- | src/game.cpp | 3 | ||||
-rw-r--r-- | src/gui/chat.cpp | 416 | ||||
-rw-r--r-- | src/gui/chat.h | 108 | ||||
-rw-r--r-- | src/gui/widgets/chattab.cpp | 312 | ||||
-rw-r--r-- | src/gui/widgets/chattab.h | 89 | ||||
-rw-r--r-- | src/gui/widgets/tabbedarea.h | 4 |
8 files changed, 520 insertions, 416 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index cafe46a7..6914fb5c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,6 +7,8 @@ tmw_CXXFLAGS = -DPKG_DATADIR=\""$(pkgdatadir)/"\" \ tmw_SOURCES = gui/widgets/avatar.cpp \ gui/widgets/avatar.h \ + gui/widgets/chattab.cpp \ + gui/widgets/chattab.h \ gui/widgets/dropdown.cpp \ gui/widgets/dropdown.h \ gui/widgets/layout.cpp \ diff --git a/src/commandhandler.cpp b/src/commandhandler.cpp index 9a9c85f3..e5f26444 100644 --- a/src/commandhandler.cpp +++ b/src/commandhandler.cpp @@ -389,7 +389,7 @@ void CommandHandler::handleMsg(const std::string &args) void CommandHandler::handleClear() { - chatWindow->clearTab(chatWindow->getFocused()); + chatWindow->clearTab(); } #ifdef TMWSERV_SUPPORT diff --git a/src/game.cpp b/src/game.cpp index d800eefe..d45387fd 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -48,6 +48,7 @@ #endif #include "player_relations.h" +#include "gui/widgets/chattab.h" #include "gui/buy.h" #include "gui/buysell.h" #include "gui/chat.h" @@ -286,6 +287,8 @@ void createGuiWindows(Network *network) emoteShortcutWindow = new ShortcutWindow("emoteShortcut", new EmoteShortcutContainer); + chatWindow->addTab(new ChatTab(std::string("General"))); + // Set initial window visibility chatWindow->setVisible((bool) config.getValue( chatWindow->getWindowName() + "Visible", true)); diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp index 597eddfd..5c15580d 100644 --- a/src/gui/chat.cpp +++ b/src/gui/chat.cpp @@ -21,42 +21,19 @@ #include <guichan/focushandler.hpp> -#include "browserbox.h" #include "chat.h" #include "chatinput.h" #include "itemlinkhandler.h" #include "recorder.h" #include "scrollarea.h" #include "sdlinput.h" -#include "windowcontainer.h" -#include "widgets/layout.h" -#include "widgets/tab.h" #include "widgets/tabbedarea.h" #include "../beingmanager.h" -#include "../commandhandler.h" -#include "../channelmanager.h" -#include "../channel.h" #include "../configuration.h" -#include "../game.h" #include "../localplayer.h" -#ifdef TMWSERV_SUPPORT -#include "../net/tmwserv/chatserver/chatserver.h" -#include "../net/tmwserv/gameserver/player.h" -#else -#include "../party.h" -#include "../net/messageout.h" -#include "../net/ea/protocol.h" -#endif - -#include "../resources/iteminfo.h" -#include "../resources/itemdb.h" - -#include "../utils/dtor.h" -#include "../utils/gettext.h" -#include "../utils/strprintf.h" #include "../utils/stringutils.h" #ifdef TMWSERV_SUPPORT @@ -82,14 +59,9 @@ ChatWindow::ChatWindow(Network * network): mChatInput->addActionListener(this); mChatTabs = new TabbedArea(); - createNewChannelTab("General"); - - place(0, 0, mChatTabs, 5, 5).setPadding(0); - place(0, 5, mChatInput, 5).setPadding(1); - Layout &layout = getLayout(); - layout.setRowHeight(0, Layout::AUTO_SET); - layout.setMargin(2); + add(mChatTabs); + add(mChatInput); loadWindowState(); @@ -102,7 +74,6 @@ ChatWindow::ChatWindow(Network * network): std::string partyPrefix = config.getValue("PartyPrefix", "$"); mPartyPrefix = (partyPrefix.empty() ? '$' : partyPrefix.at(0)); mReturnToggles = config.getValue("ReturnToggles", "0") == "1"; - mRecorder = new Recorder(this); // If the player had @assert on in the last session, ask the server to // run the @assert command for the player again. Convenience for GMs. @@ -111,6 +82,7 @@ ChatWindow::ChatWindow(Network * network): chatSend(cmd); } #endif + mRecorder = new Recorder(this); } ChatWindow::~ChatWindow() @@ -121,7 +93,6 @@ ChatWindow::~ChatWindow() config.setValue("PartyPrefix", partyPrefix); config.setValue("ReturnToggles", mReturnToggles ? "1" : "0"); delete mRecorder; - delete mParty; #endif delete mItemLinkHandler; } @@ -132,10 +103,8 @@ void ChatWindow::resetToDefaultSize() Window::resetToDefaultSize(); } -void ChatWindow::widgetResized(const gcn::Event &event) +void ChatWindow::adjustTabSize() { - Window::widgetResized(event); - const gcn::Rectangle area = getChildrenArea(); mChatInput->setPosition(mChatInput->getFrameSize(), @@ -144,34 +113,28 @@ void ChatWindow::widgetResized(const gcn::Event &event) mChatInput->setWidth(area.width - 2 * mChatInput->getFrameSize()); mChatTabs->setWidth(area.width - 2 * mChatTabs->getFrameSize()); - mChatTabs->setHeight(area.height - 2 * mChatTabs->getFrameSize()); - - const std::string &channelName = getFocused(); - ChannelMap::const_iterator chan = mChannels.find(channelName); - if (chan != mChannels.end()) { - ScrollArea *scroll = chan->second.scroll; - scroll->setWidth(area.width - 2 * scroll->getFrameSize()); - scroll->setHeight(area.height - 2 * scroll->getFrameSize() - - mChatInput->getHeight() - 5); - scroll->logic(); + mChatTabs->setHeight(area.height - 2 * mChatTabs->getFrameSize() - + (mChatInput->getHeight() + mChatInput->getFrameSize() * 2)); + + ChatTab *tab = getFocused(); + if (tab) { + gcn::Widget *content = tab->mScrollArea; + content->setSize(mChatTabs->getWidth() - 2 * content->getFrameSize(), + mChatTabs->getContainerHeight() - 2 * content->getFrameSize()); + content->logic(); } } -void ChatWindow::logic() +void ChatWindow::widgetResized(const gcn::Event &event) { - Window::logic(); + Window::widgetResized(event); - const gcn::Rectangle area = getChildrenArea(); + adjustTabSize(); +} - const std::string &channelName = getFocused(); - ChannelMap::const_iterator chan = mChannels.find(channelName); - if (chan != mChannels.end()) { - ScrollArea *scroll = chan->second.scroll; - scroll->setWidth(area.width - 2 * scroll->getFrameSize()); - scroll->setHeight(area.height - 2 * scroll->getFrameSize() - - mChatInput->getHeight() - 5); - scroll->logic(); - } +void ChatWindow::logic() +{ + Window::logic(); } void ChatWindow::chatLog(std::string line, int own, std::string channelName, @@ -183,199 +146,29 @@ void ChatWindow::chatLog(std::string line, int own, std::string channelName, #else channelName = "General"; #endif + ChatTab *tab = findTab(channelName); - ChannelMap::const_iterator chan = mChannels.find(channelName); - if (chan == mChannels.end()) - return; - - BrowserBox * const output = chan->second.browser; - ScrollArea * const scroll = chan->second.scroll; - - // Trim whitespace - trim(line); - - if (line.empty()) - return; - - CHATLOG tmp; - tmp.own = own; - tmp.nick = ""; - tmp.text = line; - - std::string::size_type pos = line.find(" : "); - if (pos != std::string::npos) - { - tmp.nick = line.substr(0, pos); - tmp.text = line.substr(pos + 3); - } - else - { - // Fix the owner of welcome message. - if (line.substr(0, 7) == "Welcome") - { - own = BY_SERVER; - } - } - - // *implements actions in a backwards compatible way* - if (own == BY_PLAYER && - tmp.text.at(0) == '*' && - tmp.text.at(tmp.text.length()-1) == '*') - { - tmp.text[0] = ' '; - tmp.text.erase(tmp.text.length() - 1); - own = ACT_IS; - } - - std::string lineColor = "##C"; - switch (own) - { - case BY_GM: - if (tmp.nick.empty()) - { - tmp.nick = std::string(_("Global announcement:")); - tmp.nick += " "; - lineColor = "##G"; - } - else - { - tmp.nick = strprintf(_("Global announcement from %s:"), - tmp.nick.c_str()); - tmp.nick += " "; - lineColor = "##1"; // Equiv. to BrowserBox::RED - } - break; - case BY_PLAYER: - tmp.nick += CAT_NORMAL; - lineColor = "##Y"; - break; - case BY_OTHER: - tmp.nick += CAT_NORMAL; - lineColor = "##C"; - break; - case BY_SERVER: - tmp.nick = _("Server:"); - tmp.nick += " "; - tmp.text = line; - lineColor = "##S"; - break; - case BY_CHANNEL: - tmp.nick = ""; - // TODO: Use a predefined color - lineColor = "##2"; // Equiv. to BrowserBox::GREEN - break; -#ifdef EATHENA_SUPPORT - case BY_PARTY: - tmp.nick += CAT_NORMAL; - lineColor = "##P"; - break; -#endif - case ACT_WHISPER: - tmp.nick = strprintf(_("%s whispers:"), tmp.nick.c_str()); - tmp.nick += " "; - lineColor = "##W"; - break; - case ACT_IS: - tmp.nick += CAT_IS; - lineColor = "##I"; - break; - case BY_LOGGER: - tmp.nick = ""; - tmp.text = line; - lineColor = "##L"; - break; - } - - if (tmp.nick == ": ") - { - tmp.nick = ""; - lineColor = "##S"; - } - -#ifdef EATHENA_SUPPORT - if (tmp.nick.empty() && tmp.text.substr(0, 17) == "Visible GM status") - { - player_node->setGM(); - } -#endif - - // Get the current system time - time_t t; - time(&t); - - // Format the time string properly - std::stringstream timeStr; - timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "") - << (int) (((t / 60) / 60) % 24) - << ":" << (((t / 60) % 60 < 10) ? "0" : "") - << (int) ((t / 60) % 60) - << "] "; - - // Check for item link - std::string::size_type start = tmp.text.find('['); - while (start != std::string::npos && tmp.text[start+1] != '@') - { - std::string::size_type end = tmp.text.find(']', start); - if (start+1 != end && end != std::string::npos) - { - // Catch multiple embeds and ignore them - // so it doesn't crash the client. - while ((tmp.text.find('[', start + 1) != std::string::npos) && - (tmp.text.find('[', start + 1) < end)) - { - start = tmp.text.find('[', start + 1); - } - - std::string temp = tmp.text.substr(start+1, end - start - 1); - - trim(temp); - - for (unsigned int i = 0; i < temp.size(); i++) - { - temp[i] = (char) tolower(temp[i]); - } - - const ItemInfo itemInfo = ItemDB::get(temp); - if (itemInfo.getName() != _("Unknown item")) - { - tmp.text.insert(end, "@@"); - tmp.text.insert(start+1, "|"); - tmp.text.insert(start+1, toString(itemInfo.getId())); - tmp.text.insert(start+1, "@@"); - } - } - start = tmp.text.find('[', start + 1); - } - - line = lineColor + timeStr.str() + tmp.nick + tmp.text; - - // We look if the Vertical Scroll Bar is set at the max before - // adding a row, otherwise the max will always be a row higher - // at comparison. - if (scroll->getVerticalScrollAmount() >= scroll->getVerticalMaxScroll()) - { - output->addRow(line); - scroll->setVerticalScrollAmount(scroll->getVerticalMaxScroll()); - } - else - { - output->addRow(line); - } + tab->chatLog(line, own, ignoreRecord); +} - scroll->logic(); - mRecorder->record(line.substr(3)); +ChatTab* ChatWindow::getFocused() const +{ + return dynamic_cast<ChatTab*>(mChatTabs->getSelectedTab()); } -const std::string &ChatWindow::getFocused() const +void ChatWindow::clearTab(ChatTab* tab) { - return mChatTabs->getSelectedTab()->getCaption(); + if (tab) tab->clearText(); } void ChatWindow::clearTab(const std::string &tab) { - ChannelMap::const_iterator chan = mChannels.find(tab); - if (chan != mChannels.end()) - chan->second.browser->clearRows(); + clearTab(findTab(tab)); +} + +void ChatWindow::clearTab() +{ + clearTab(getFocused()); } void ChatWindow::action(const gcn::ActionEvent &event) @@ -444,130 +237,43 @@ bool ChatWindow::isInputFocused() return mChatInput->isFocused(); } -void ChatWindow::removeChannel(short channelId) +ChatTab* ChatWindow::findTab(const std::string &tabName) { - removeChannel(channelManager->findById(channelId)); + return mTabs[tabName]; } -void ChatWindow::removeChannel(const std::string &channelName) +void ChatWindow::removeTab(ChatTab *tab) { - removeChannel(channelManager->findByName(channelName)); + mTabs.erase(tab->getCaption()); + mChatTabs->removeTab(tab); } -void ChatWindow::removeChannel(Channel *channel) +void ChatWindow::removeTab(const std::string &tabName) { - if (channel) - { - Tab *tab = mChatTabs->getTab(channel->getName()); - if (!tab) - return; - clearTab(channel->getName()); - mChatTabs->removeTab(tab); - mChannels.erase(channel->getName()); - channelManager->removeChannel(channel); - - logic(); - } + ChatTab *tab = findTab(tabName); + if (tab) removeTab(tab); } -void ChatWindow::createNewChannelTab(const std::string &channelName) +void ChatWindow::addTab(ChatTab *tab) { - // Create new channel - BrowserBox *textOutput = new BrowserBox(BrowserBox::AUTO_WRAP); - textOutput->setOpaque(false); - textOutput->disableLinksAndUserColors(); - textOutput->setMaxRow((int) config.getValue("ChatLogLength", 0)); - ScrollArea *scrollArea = new ScrollArea(textOutput); - scrollArea->setPosition(scrollArea->getFrameSize(), scrollArea->getFrameSize()); - scrollArea->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER, gcn::ScrollArea::SHOW_ALWAYS); - scrollArea->setOpaque(false); - scrollArea->setWidth(getChildrenArea().width - 2 * scrollArea->getFrameSize()); - scrollArea->setHeight(getChildrenArea().height - 2 * scrollArea->getFrameSize() - - mChatInput->getHeight() - 5); - scrollArea->logic(); - textOutput->setWidth(scrollArea->getChildrenArea().width); - textOutput->setHeight(scrollArea->getChildrenArea().height); - - // Add channel to the tabbed area - mChatTabs->addTab(channelName, scrollArea); - mChannels.insert( - std::make_pair(channelName, ChatArea(textOutput, scrollArea))); + // Make sure we don't end up with duplicates in the gui + removeTab(tab->getCaption()); + + mTabs[tab->getCaption()] = tab; + + mChatTabs->addTab(tab, tab->mScrollArea); + + if (mTabs.size() == 1) + adjustTabSize(); // Update UI logic(); } -void ChatWindow::sendToChannel(short channelId, - const std::string &user, - const std::string &msg) -{ - Channel *channel = channelManager->findById(channelId); - if (channel) - { - std::string channelName = channel->getName(); - chatLog(user + ": " + msg, user == player_node->getName() ? BY_PLAYER : BY_OTHER, channelName); - mChatTabs->getTab(channelName)->setHighlighted(true); - } -} - void ChatWindow::chatSend(std::string &msg) { - trim(msg); - - if (msg.empty()) return; - -#ifdef EATHENA_SUPPORT - // Send party message - if (msg.at(0) == mPartyPrefix) - { - msg.erase(0, 1); - std::size_t length = msg.length() + 1; - - if (length == 0) - { - chatLog(_("Trying to send a blank party message."), BY_SERVER); - return; - } - MessageOut outMsg(mNetwork); - - outMsg.writeInt16(CMSG_PARTY_MESSAGE); - outMsg.writeInt16(length + 4); - outMsg.writeString(msg, length); - return; - } -#endif - - // Prepare ordinary message - if (msg[0] != '/') - { -#ifdef TMWSERV_SUPPORT - if (getFocused() == "General") - { - Net::GameServer::Player::say(msg); - } - else - { - Channel *channel = channelManager->findByName(getFocused()); - if (channel) - { - Net::ChatServer::chat(channel->getId(), msg); - } - } -#else - msg = player_node->getName() + " : " + msg; - - MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_CHAT_MESSAGE); - // Added + 1 in order to let eAthena parse admin commands correctly - outMsg.writeInt16(msg.length() + 4 + 1); - outMsg.writeString(msg, msg.length() + 1); - return; -#endif - } - else - { - commandHandler->handleCommand(std::string(msg, 1)); - } + ChatTab *tab = getFocused(); + tab->chatSend(msg); } void ChatWindow::doPresent() @@ -617,18 +323,8 @@ void ChatWindow::scroll(int amount) if (!isVisible()) return; - ChannelMap::const_iterator chan = mChannels.find(getFocused()); - if (chan == mChannels.end()) - return; - - BrowserBox *browser = chan->second.browser; - ScrollArea *scroll = chan->second.scroll; - - int range = scroll->getHeight() / 8 * amount; - gcn::Rectangle scr; - scr.y = scroll->getVerticalScrollAmount() + range; - scr.height = abs(range); - browser->showPart(scr); + ChatTab *tab = getFocused(); + if (tab) tab->scroll(amount); } void ChatWindow::keyPressed(gcn::KeyEvent &event) diff --git a/src/gui/chat.h b/src/gui/chat.h index 2bbf32ae..fa63cedd 100644 --- a/src/gui/chat.h +++ b/src/gui/chat.h @@ -28,18 +28,22 @@ #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> +#include <guichan/widget.hpp> +#include <guichan/widgetlistener.hpp> + +#include "widgets/chattab.h" #include "window.h" class BrowserBox; class Channel; +class ChatTab; class Recorder; class ScrollArea; class TabbedArea; class ItemLinkHandler; #ifdef EATHENA_SUPPORT class Network; -class Party; #endif enum @@ -67,6 +71,14 @@ enum #define DEFAULT_CHAT_WINDOW_SCROLL 7 // 1 means `1/8th of the window size'. +/** One item in the chat log */ +struct CHATLOG +{ + std::string nick; + std::string text; + int own; +}; + /** * The chat window. * @@ -119,16 +131,26 @@ class ChatWindow : public Window, bool ignoreRecord = false); /** - * Gets the focused tab's name + * Gets the focused tab. */ - const std::string &getFocused() const; + ChatTab* getFocused() const; /** - * Clear the tab with the given name + * Clear the tab with the given name. */ void clearTab(const std::string &tab); /** + * Clear the given tab. + */ + void clearTab(ChatTab* tab); + + /** + * Clear the current tab. + */ + void clearTab(); + + /** * Performs action. */ void action(const gcn::ActionEvent &event); @@ -146,15 +168,15 @@ class ChatWindow : public Window, */ bool isInputFocused(); - /** Called to remove the channel from the channel manager */ - void removeChannel(short channelId); + ChatTab* findTab(const std::string &tabName); - void removeChannel(const std::string &channelName); + /** Remove the given tab from the window */ + void removeTab(ChatTab *tab); - void removeChannel(Channel *channel); + void removeTab(const std::string &tabName); - /** Called to create a new channel tab */ - void createNewChannelTab(const std::string &channelName); + /** Add the tab to the window */ + void addTab(ChatTab *tab); /** Called to output text to a specific channel */ void sendToChannel(short channel, @@ -162,9 +184,7 @@ class ChatWindow : public Window, const std::string &msg); /** - * Determines whether the message is a command or message, then - * sends the given message to the game server to be said, or to the - * command handler + * Passes the text to the current tab as input * * @param msg The message text which is to be sent. * @@ -212,61 +232,39 @@ class ChatWindow : public Window, void doPresent(); - private: + protected: + friend class ChatTab; + + void adjustTabSize(); + #ifdef EATHENA_SUPPORT Network *mNetwork; + char mPartyPrefix; /**< Messages beginning with the prefix are sent to + the party */ #endif - bool mTmpVisible; - - int mItems; - int mItemsKeep; - - /** One item in the chat log */ - struct CHATLOG - { - std::string nick; - std::string text; - int own; - }; - - /** - * A structure combining a BrowserBox with its ScrollArea. - */ - struct ChatArea - { - ChatArea(BrowserBox *b, ScrollArea *s): - browser(b), scroll(s) - {} - - BrowserBox *browser; - ScrollArea *scroll; - }; - /** Used for showing item popup on clicking links **/ ItemLinkHandler *mItemLinkHandler; - - /** Tabbed area for holding each channel. */ - TabbedArea *mChatTabs; + Recorder *mRecorder; /** Input box for typing chat messages. */ gcn::TextField *mChatInput; - typedef std::map<const std::string, ChatArea> ChannelMap; + private: + bool mTmpVisible; + + /** Tabbed area for holding each channel. */ + TabbedArea *mChatTabs; + + typedef std::map<const std::string, ChatTab*> TabMap; /** Map each tab to its browser and scroll area. */ - ChannelMap mChannels; + TabMap mTabs; typedef std::list<std::string> History; typedef History::iterator HistoryIterator; - History mHistory; /**< Command history */ - HistoryIterator mCurHist; /**< History iterator */ - Recorder *mRecorder; /**< Recording class */ - bool mReturnToggles; /**< Marks whether <Return> toggles the chat - log or not */ -#ifdef EATHENA_SUPPORT - char mPartyPrefix; /**< Messages beginning with the prefix are - sent to the party */ - Party *mParty; -#endif + History mHistory; /**< Command history. */ + HistoryIterator mCurHist; /**< History iterator. */ + bool mReturnToggles; /**< Marks whether <Return> toggles the chat log + or not */ }; extern ChatWindow *chatWindow; diff --git a/src/gui/widgets/chattab.cpp b/src/gui/widgets/chattab.cpp new file mode 100644 index 00000000..746518ad --- /dev/null +++ b/src/gui/widgets/chattab.cpp @@ -0,0 +1,312 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <guichan/widgets/label.hpp> + +#include "chattab.h" +#include "layouthelper.h" + +#include "../browserbox.h" +#include "../chatinput.h" +#include "../itemlinkhandler.h" +#include "../recorder.h" +#include "../scrollarea.h" + +#include "../../commandhandler.h" +#include "../../configuration.h" +#include "../../localplayer.h" + +#ifdef TMWSERV_SUPPORT +#include "../../net/tmwserv/chatserver/chatserver.h" +#include "../../net/tmwserv/gameserver/player.h" +#else +#include "../../net/messageout.h" +#include "../../net/ea/protocol.h" +#endif + +#include "../../resources/iteminfo.h" +#include "../../resources/itemdb.h" + +#include "../../utils/strprintf.h" +#include "../../utils/stringutils.h" + +ChatTab::ChatTab(const std::string &name) : Tab() +{ + setCaption(name); + + mTextOutput = new BrowserBox; + mTextOutput->setOpaque(false); + mTextOutput->setMaxRow((int) config.getValue("ChatLogLength", 0)); + mTextOutput->setLinkHandler(chatWindow->mItemLinkHandler); + + mScrollArea = new ScrollArea(mTextOutput); + mScrollArea->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER, + gcn::ScrollArea::SHOW_ALWAYS); + mScrollArea->setScrollAmount(0, 1); + mScrollArea->setOpaque(false); +} + +ChatTab::~ChatTab() +{ + delete mTextOutput; + delete mScrollArea; +} + +void ChatTab::chatLog(std::string line, int own, bool ignoreRecord) +{ + // Trim whitespace + trim(line); + + if (line.empty()) + return; + + CHATLOG tmp; + tmp.own = own; + tmp.nick = ""; + tmp.text = line; + + std::string::size_type pos = line.find(" : "); + if (pos != std::string::npos) + { + tmp.nick = line.substr(0, pos); + tmp.text = line.substr(pos + 3); + } + else + { + // Fix the owner of welcome message. + if (line.substr(0, 7) == "Welcome") + { + own = BY_SERVER; + } + } + + // *implements actions in a backwards compatible way* + if (own == BY_PLAYER && + tmp.text.at(0) == '*' && + tmp.text.at(tmp.text.length()-1) == '*') + { + tmp.text[0] = ' '; + tmp.text.erase(tmp.text.length() - 1); + own = ACT_IS; + } + + std::string lineColor = "##C"; + switch (own) + { + case BY_GM: + if (tmp.nick.empty()) + { + tmp.nick = std::string(_("Global announcement:")); + tmp.nick += " "; + lineColor = "##G"; + } + else + { + tmp.nick = strprintf(_("Global announcement from %s:"), + tmp.nick.c_str()); + tmp.nick += " "; + lineColor = "##1"; // Equiv. to BrowserBox::RED + } + break; + case BY_PLAYER: + tmp.nick += CAT_NORMAL; + lineColor = "##Y"; + break; + case BY_OTHER: + tmp.nick += CAT_NORMAL; + lineColor = "##C"; + break; + case BY_SERVER: + tmp.nick = _("Server:"); + tmp.nick += " "; + tmp.text = line; + lineColor = "##S"; + break; + case BY_CHANNEL: + tmp.nick = ""; + // TODO: Use a predefined color + lineColor = "##2"; // Equiv. to BrowserBox::GREEN + break; +#ifdef EATHENA_SUPPORT + case BY_PARTY: + tmp.nick += CAT_NORMAL; + lineColor = "##P"; + break; +#endif + case ACT_WHISPER: + tmp.nick = strprintf(_("%s whispers:"), tmp.nick.c_str()); + tmp.nick += " "; + lineColor = "##W"; + break; + case ACT_IS: + tmp.nick += CAT_IS; + lineColor = "##I"; + break; + case BY_LOGGER: + tmp.nick = ""; + tmp.text = line; + lineColor = "##L"; + break; + } + + if (tmp.nick == ": ") + { + tmp.nick = ""; + lineColor = "##S"; + } + +#ifdef EATHENA_SUPPORT + if (tmp.nick.empty() && tmp.text.substr(0, 17) == "Visible GM status") + { + player_node->setGM(); + } +#endif + + // Get the current system time + time_t t; + time(&t); + + // Format the time string properly + std::stringstream timeStr; + timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "") + << (int) (((t / 60) / 60) % 24) + << ":" << (((t / 60) % 60 < 10) ? "0" : "") + << (int) ((t / 60) % 60) + << "] "; + + line = lineColor + timeStr.str() + tmp.nick + tmp.text; + + // We look if the Vertical Scroll Bar is set at the max before + // adding a row, otherwise the max will always be a row higher + // at comparison. + if (mScrollArea->getVerticalScrollAmount() >= mScrollArea->getVerticalMaxScroll()) + { + mTextOutput->addRow(line); + mScrollArea->setVerticalScrollAmount(mScrollArea->getVerticalMaxScroll()); + } + else + { + mTextOutput->addRow(line); + } + + mScrollArea->logic(); + chatWindow->mRecorder->record(line.substr(3)); +} + +void ChatTab::chatSend(std::string &msg) +{ + trim(msg); + + if (msg.empty()) return; + +#ifdef EATHENA_SUPPORT + // Send party message + if (msg.at(0) == chatWindow->mPartyPrefix) + { + msg.erase(0, 1); + std::size_t length = msg.length() + 1; + + if (length == 0) + { + chatLog(_("Trying to send a blank party message."), BY_SERVER, true); + return; + } + MessageOut outMsg(chatWindow->mNetwork); + + outMsg.writeInt16(CMSG_PARTY_MESSAGE); + outMsg.writeInt16(length + 4); + outMsg.writeString(msg, length); + return; + } +#endif + + // Check for item link + std::string::size_type start = msg.find('['); + while (start != std::string::npos && msg[start+1] != '@') + { + std::string::size_type end = msg.find(']', start); + if (start+1 != end && end != std::string::npos) + { + // Catch multiple embeds and ignore them + // so it doesn't crash the client. + while ((msg.find('[', start + 1) != std::string::npos) && + (msg.find('[', start + 1) < end)) + { + start = msg.find('[', start + 1); + } + + std::string temp = msg.substr(start + 1, end - start - 1); + + toLower(trim(temp)); + + const ItemInfo itemInfo = ItemDB::get(temp); + if (itemInfo.getName() != _("Unknown item")) + { + msg.insert(end, "@@"); + msg.insert(start+1, "|"); + msg.insert(start+1, toString(itemInfo.getId())); + msg.insert(start+1, "@@"); + } + } + start = msg.find('[', start + 1); + } + + + // Prepare ordinary message + if (msg[0] != '/') + { +#ifdef TMWSERV_SUPPORT + Net::GameServer::Player::say(msg); + /*Channel *channel = channelManager->findByName(getFocused()); + if (channel) + { + Net::ChatServer::chat(channel->getId(), msg); + }*/ +#else + msg = player_node->getName() + " : " + msg; + + MessageOut outMsg(chatWindow->mNetwork); + outMsg.writeInt16(CMSG_CHAT_MESSAGE); + // Added + 1 in order to let eAthena parse admin commands correctly + outMsg.writeInt16(msg.length() + 4 + 1); + outMsg.writeString(msg, msg.length() + 1); + return; +#endif + } + else + { + commandHandler->handleCommand(std::string(msg, 1)); + } +} + +void ChatTab::scroll(int amount) +{ + int range = mScrollArea->getHeight() / 8 * amount; + gcn::Rectangle scr; + scr.y = mScrollArea->getVerticalScrollAmount() + range; + scr.height = abs(range); + mTextOutput->showPart(scr); +} + +void ChatTab::clearText() +{ + mTextOutput->clearRows(); +} diff --git a/src/gui/widgets/chattab.h b/src/gui/widgets/chattab.h new file mode 100644 index 00000000..dd660884 --- /dev/null +++ b/src/gui/widgets/chattab.h @@ -0,0 +1,89 @@ +/* + * The Mana World + * Copyright (C) 2009 The Mana World Development Team + * + * This file is part of The Mana World. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CHATTAB_H +#define CHATTAB_H + +#include <guichan/widgets/container.hpp> + +#include "tab.h" + +#include "../chat.h" + +class BrowserBox; +class Recorder; +class ScrollArea; + +/** + * A tab for the chat window. This is special to ease chat handling. + */ +class ChatTab : public Tab +{ + public: + /** + * Constructor. + */ + ChatTab(const std::string &name); + + /** + * Destructor. + */ + ~ChatTab(); + + /** + * Adds a line of text to our message list. Parameters: + * + * @param line Text message. + * @param own Type of message (usually the owner-type). + * @param channelName which channel to send the message to. + * @param ignoreRecord should this not be recorded? + */ + void chatLog(std::string line, int own, bool ignoreRecord); + + /** + * Determines whether the message is a command or message, then + * sends the given message to the game server to be said, or to the + * command handler + * + * @param msg The message text which is to be sent. + * + */ + void chatSend(std::string &msg); + + /** + * Scrolls the chat window + * + * @param amount direction and amount to scroll. Negative numbers scroll + * up, positive numbers scroll down. The absolute amount indicates the + * amount of 1/8ths of chat window real estate that should be scrolled. + */ + void scroll(int amount); + + void clearText(); + + protected: + friend class ChatWindow; + ScrollArea *mScrollArea; + BrowserBox *mTextOutput; + //Recorder *mRecorder; +}; + +#endif // CHATTAB_H diff --git a/src/gui/widgets/tabbedarea.h b/src/gui/widgets/tabbedarea.h index 6e96a1c4..dffbd36b 100644 --- a/src/gui/widgets/tabbedarea.h +++ b/src/gui/widgets/tabbedarea.h @@ -22,6 +22,8 @@ #ifndef TABBEDAREA_H #define TABBEDAREA_H +#include <guichan/widget.hpp> +#include <guichan/widgets/container.hpp> #include <guichan/widgets/tabbedarea.hpp> #include <string> @@ -83,6 +85,8 @@ class TabbedArea : public gcn::TabbedArea */ void logic(); + int getContainerHeight() { return mWidgetContainer->getHeight(); } + private: typedef std::vector< std::pair<gcn::Tab*, gcn::Widget*> > TabContainer; }; |