summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/commandhandler.cpp2
-rw-r--r--src/game.cpp3
-rw-r--r--src/gui/chat.cpp416
-rw-r--r--src/gui/chat.h108
-rw-r--r--src/gui/widgets/chattab.cpp312
-rw-r--r--src/gui/widgets/chattab.h89
-rw-r--r--src/gui/widgets/tabbedarea.h4
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;
};