GLWChannelView.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <GLW/GLWChannelView.h>
00022 #include <GLW/GLWFont.h>
00023 #include <GLW/GLWPanel.h>
00024 #include <GLW/GLWColors.h>
00025 #include <GLEXT/GLState.h>
00026 #include <image/ImageFactory.h>
00027 #include <XML/XMLParser.h>
00028 #include <common/Keyboard.h>
00029 #include <common/ToolTipResource.h>
00030 #include <client/ClientChannelManager.h>
00031 #include <client/ScorchedClient.h>
00032 #include <sound/SoundUtils.h>
00033 #include <tank/TankContainer.h>
00034 #include <lang/LangResource.h>
00035 #include <lang/LangParam.h>
00036 
00037 GLWChannelViewI::~GLWChannelViewI()
00038 {
00039 }
00040 
00041 REGISTER_CLASS_SOURCE(GLWChannelView);
00042 
00043 GLWChannelView::GLWChannelView() : 
00044         init_(false), 
00045         visibleLines_(5), totalLines_(50),
00046         displayTime_(10.0f),
00047         fontSize_(12.0f), outlineFontSize_(14.0f), lineDepth_(18),
00048         currentVisible_(0), lastChannelId_(1), lastWhisperSrc_(0),
00049         alignTop_(false), parentSized_(false), splitLargeLines_(false),
00050         scrollPosition_(-1), allowScroll_(false), 
00051         showChannelName_(true), showChannelNumber_(true),
00052         upButton_(x_ + 2.0f, y_ + 1.0f, 12.0f, 12.0f),
00053         downButton_(x_ + 2.0f, y_ + 1.0f, 12.0f, 12.0f),
00054         resetButton_(x_ + 2.0f, y_ + 1.0f, 14.0f, 14.0f),
00055         scrollUpKey_(0), scrollDownKey_(0), scrollResetKey_(0),
00056         handler_(0),
00057         createdTexture_(false)
00058 {
00059         upButton_.setHandler(this);
00060         downButton_.setHandler(this);
00061         resetButton_.setHandler(this);
00062 
00063         upButton_.setToolTip(new ToolTipResource(
00064                 ToolTip::ToolTipAlignLeft | ToolTip::ToolTipHelp, 
00065                 "CHAT_PREVIOUS", "Chat Previous", 
00066                 "CHAT_PREVIOUS_TOOLTIP", "Show previous chat entry"));
00067         downButton_.setToolTip(new ToolTipResource(
00068                 ToolTip::ToolTipAlignLeft | ToolTip::ToolTipHelp, 
00069                 "CHAT_NEXT", "Chat Next", 
00070                 "CHAT_NEXT_TOOLTIP", "Show next chat entry"));
00071         resetButton_.setToolTip(new ToolTipResource(
00072                 ToolTip::ToolTipAlignLeft | ToolTip::ToolTipHelp, 
00073                 "CHAT_LAST", "Chat Last", 
00074                 "CHAT_LAST_TOOLTIP", "View end of the chat log, \n"
00075                 "hide all elapsed entries"));
00076 }
00077 
00078 GLWChannelView::~GLWChannelView()
00079 {
00080 }
00081 
00082 GLWChannelView::CurrentChannelEntry *GLWChannelView::getChannel(const std::string &channelName)
00083 {
00084         std::list<CurrentChannelEntry>::iterator itor;
00085         for (itor = currentChannels_.begin();
00086                 itor != currentChannels_.end();
00087                 itor++)
00088         {
00089                 CurrentChannelEntry &current = *itor;
00090                 if (channelName == current.channel) return &current;
00091                 if (current.id == atoi(channelName.c_str())) return &current;
00092         }
00093         return 0;
00094 }
00095 
00096 void GLWChannelView::registeredForChannels(
00097         std::list<ChannelDefinition> &registeredChannels,
00098         std::list<ChannelDefinition> &availableChannels)
00099 {
00100         // Some not efficient stuff....
00101         std::list<CurrentChannelEntry> oldCurrentChannels = currentChannels_;
00102         std::list<BaseChannelEntry> oldAvailableChannels = availableChannels_;
00103         currentChannels_.clear();
00104         availableChannels_.clear();
00105 
00106         // For all of the new channels
00107         {
00108                 std::list<ChannelDefinition>::iterator itor;
00109                 for (itor = registeredChannels.begin();
00110                         itor != registeredChannels.end();
00111                         itor++)
00112                 {
00113                         std::string channel = itor->getChannel();
00114 
00115                         // Find out if we were already in this channel
00116                         bool found = false;
00117                         std::list<CurrentChannelEntry>::iterator olditor;
00118                         for (olditor = oldCurrentChannels.begin();
00119                                 olditor != oldCurrentChannels.end();
00120                                 olditor++)
00121                         {
00122                                 CurrentChannelEntry &oldEntry = (*olditor);
00123                                 if (channel == oldEntry.channel)
00124                                 {
00125                                         // Add the existing channel, under the existing number
00126                                         found = true;
00127                                         currentChannels_.push_back(oldEntry);
00128                                         break;
00129                                 }
00130                         }
00131                         if (!found)
00132                         {
00133                                 // Add a new channel with a new number
00134                                 CurrentChannelEntry newEntry;
00135                                 newEntry.id = lastChannelId_++;
00136                                 newEntry.color = Vector(0.8f, 0.8f, 0.8f);
00137                                 newEntry.channel = channel;
00138                                 newEntry.type = itor->getType();
00139 
00140                                 std::map<std::string, Vector>::iterator colorItor =
00141                                         channelColors_.find(channel.c_str());
00142                                 if (colorItor != channelColors_.end()) 
00143                                 {
00144                                         newEntry.color = colorItor->second;
00145                                 }
00146 
00147                                 currentChannels_.push_back(newEntry);
00148                         }       
00149                 }
00150         }
00151 
00152         // For all of the available channels
00153         {
00154                 std::list<ChannelDefinition>::iterator itor;
00155                 for (itor = availableChannels.begin();
00156                         itor != availableChannels.end();
00157                         itor++)
00158                 {
00159                         std::string channel = itor->getChannel();
00160 
00161                         // Add this channel to list of available
00162                         BaseChannelEntry newEntry;
00163                         newEntry.channel = channel;
00164                         newEntry.type = itor->getType();
00165                         availableChannels_.push_back(newEntry);
00166                 }
00167         }
00168 
00169         if (handler_) handler_->channelsChanged(getId());
00170 }
00171 
00172 void GLWChannelView::joinChannel(const std::string &channelName)
00173 {
00174         std::list<std::string> channels;
00175         formCurrentChannelList(channels);
00176         channels.push_back(channelName);
00177 
00178         ClientChannelManager::instance()->changeRegistration(this, channels);
00179 }
00180 
00181 void GLWChannelView::leaveChannel(const std::string &channelName)
00182 {
00183         std::list<std::string> channels;
00184         formCurrentChannelList(channels);
00185         channels.remove(channelName);
00186 
00187         ClientChannelManager::instance()->changeRegistration(this, channels);
00188 }
00189 
00190 void GLWChannelView::channelText(ChannelText &channelText)
00191 {
00192         if (!(channelText.getFlags() & ChannelText::eNoSound) &&
00193                 !textSound_.empty())
00194         {
00195                 CACHE_SOUND(sound, S3D::getDataFile(textSound_.c_str()));
00196                 SoundUtils::playRelativeSound(VirtualSoundPriority::eText, sound);      
00197         }
00198 
00199         CurrentChannelEntry *channel = getChannel(channelText.getChannel());
00200         if (!channel) return;
00201 
00202         Tank *tank = ScorchedClient::instance()->getTankContainer().
00203                 getTankById(channelText.getSrcPlayerId());
00204         if (tank)
00205         {
00206                 if (channel->type & ChannelDefinition::eWhisperChannel)
00207                 {
00208                         if (tank != ScorchedClient::instance()->getTankContainer().getCurrentTank())
00209                         {
00210                                 lastWhisperSrc_ = tank->getPlayerId();
00211                         }
00212                 }
00213         }
00214 
00215         LangString channelName;
00216         if (showChannelNumber_)
00217         {
00218                 channelName.append(LANG_PARAM_1("{0}. ", channel->id));
00219         }
00220         if (showChannelName_)
00221         {
00222                 channelName.append(LANG_PARAM_1("[c:{0}]", channel->channel));
00223         }
00224         if (tank)
00225         {
00226                 channelName.append(LANG_PARAM_1("[p:{0}]", tank->getTargetName()));
00227         }
00228         if (channelText.getAdminPlayer()[0])
00229         {
00230                 channelName.append(LANG_PARAM_1("[a:{0}]", channelText.getAdminPlayer()));
00231         }
00232         if (!channelName.empty())
00233         {
00234                 channelName.append(LANG_STRING(" : "));
00235         }
00236         channelName.append(channelText.getMessage());
00237 
00238         GLWChannelViewTextRenderer chanText(this);
00239         chanText.parseText(ScorchedClient::instance()->getContext(), channelName);
00240         
00241         bool firstTime = true;
00242         int currentLen = 0;
00243         const LangString &text = chanText.getString();
00244         int totalLen = (int) text.size();
00245         while (currentLen < totalLen)
00246         {
00247                 // Get the next split position
00248                 int partLen = splitLine(&text[currentLen]);
00249                 bool nl=(text[currentLen + partLen - 1] == '\n');
00250 
00251                 // Create the new text and add it
00252                 GLWChannelViewTextRenderer newText(this);
00253                 newText.subset(chanText, currentLen, (nl?partLen-1:partLen));
00254                 addInfo(channel->color, newText);
00255 
00256                 // Increment the current position
00257                 currentLen += partLen;
00258         }
00259 }
00260 
00261 void GLWChannelView::buttonDown(unsigned int id)
00262 {
00263         if (!allowScroll_) return;
00264 
00265         if (id == upButton_.getId())
00266         {
00267                 scrollPosition_ ++;
00268                 if (scrollPosition_ > (int) textLines_.size() - 1)
00269                         scrollPosition_ = (int) textLines_.size() - 1;
00270         }
00271         else if (id == downButton_.getId())
00272         {
00273                 scrollPosition_ --;
00274                 if (scrollPosition_ < 0) scrollPosition_ = 0;
00275         }
00276         else
00277         {
00278                 scrollPosition_ = -1;
00279         }
00280 }
00281 
00282 int GLWChannelView::splitLine(const LangString &message)
00283 {
00284         int lastSpace = 0;
00285         int totalLen = (int) message.size();
00286         for (int len=1; len<totalLen; len++)
00287         {
00288                 float width = 0.0f;
00289                 if (splitLargeLines_)
00290                 {
00291                         width = GLWFont::instance()->getGameFont()->
00292                                 getWidth(outlineFontSize_, message, len);
00293                 }
00294 
00295                 if (width > w_)
00296                 {
00297                         // If there is a space within the last 15 characters split to it
00298                         if (lastSpace && (len - lastSpace < 15)) 
00299                         {
00300                                 return lastSpace;
00301                         }
00302                         else
00303                         {
00304                                 // Else just split where we are now
00305                                 return len - 1;
00306                         }
00307                 }
00308 
00309                 if (message[len] == '\n')
00310                 {
00311                         return len + 1;
00312                 }
00313                 if (message[len] == ' ')
00314                 {
00315                         lastSpace = len + 1;
00316                 }
00317         }
00318 
00319         // The whole message fits, split to the end of the message
00320         return totalLen;
00321 }
00322 
00323 void GLWChannelView::addInfo(Vector &color, GLWChannelViewTextRenderer &text)
00324 {
00325         GLWChannelViewEntry entry;
00326         entry.text = text;
00327         entry.timeRemaining = displayTime_;
00328         entry.color = color;
00329         textLines_.push_front(entry);
00330 
00331         if (scrollPosition_ > 0)
00332         {
00333                 scrollPosition_ ++;
00334                 if (scrollPosition_ > (int) textLines_.size() - 1)
00335                         scrollPosition_ = (int) textLines_.size() - 1;
00336         }
00337 
00338         if (textLines_.size() > (unsigned int) totalLines_)
00339         {
00340                 textLines_.pop_back();
00341         }
00342 }
00343 
00344 void GLWChannelView::simulate(float frameTime)
00345 {
00346         currentVisible_ = 0;
00347         int count = 0;
00348         std::list<GLWChannelViewEntry>::iterator itor;
00349         for (itor = textLines_.begin();
00350                 itor != textLines_.end() && count < visibleLines_;
00351                 itor++, count++)
00352         {
00353                 GLWChannelViewEntry &entry = (*itor);
00354                 entry.timeRemaining -= frameTime;
00355                 if (entry.timeRemaining > 0.0f) currentVisible_ ++;
00356         }
00357 }
00358 
00359 void GLWChannelView::setX(float x)
00360 {
00361         GLWidget::setX(x);
00362         upButton_.setX(x_ + 1.0f);
00363         downButton_.setX(x_ + 1.0f);
00364         resetButton_.setX(x_ + 1.0f);
00365 }
00366 
00367 void GLWChannelView::setY(float y)
00368 {
00369         GLWidget::setY(y);
00370         upButton_.setY(y_ + 36.0f);
00371         downButton_.setY(y_ + 24.0f);
00372         resetButton_.setY(y_ + 6.0f);
00373 }
00374 
00375 void GLWChannelView::draw()
00376 {
00377         GLWidget::draw();
00378         if (!createdTexture_)
00379         {
00380                 createdTexture_ = true;
00381                 ImageHandle upImg = ImageFactory::loadAlphaImageHandle(
00382                         S3D::getDataFile("data/windows/arrow_u.png"));
00383                 ImageHandle downImg = ImageFactory::loadAlphaImageHandle(
00384                         S3D::getDataFile("data/windows/arrow_d.png"));
00385                 ImageHandle resetImg = ImageFactory::loadAlphaImageHandle(
00386                         S3D::getDataFile("data/windows/arrow_s.png"));
00387 
00388                 upTexture_.create(upImg, false);
00389                 downTexture_.create(downImg, false);
00390                 resetTexture_.create(resetImg, false);
00391 
00392                 upButton_.setTexture(&upTexture_);
00393                 downButton_.setTexture(&downTexture_);
00394                 resetButton_.setTexture(&resetTexture_);
00395         }
00396 
00397         if (allowScroll_)
00398         {
00399                 upButton_.draw();
00400                 downButton_.draw();
00401                 resetButton_.draw();
00402         }
00403 
00404         if (!init_)
00405         {
00406                 ClientChannelManager::instance()->registerClient(this, startupChannels_);
00407                 init_ = true;
00408                 if (parent_ && parentSized_)
00409                 {
00410                         w_ = parent_->getW();
00411                         h_ = parent_->getH();
00412                 }
00413         }
00414 
00415         // Check if there is anything to draw
00416         if (textLines_.empty()) return;
00417 
00418         // Find the start of the area to draw to
00419         GLState currentStateBlend(GLState::TEXTURE_ON | 
00420                 GLState::BLEND_ON | GLState::DEPTH_OFF);
00421         float start = y_ + 8.0f; //lineDepth_;
00422         if (alignTop_)
00423         {
00424                 start = y_ + h_ - float(currentVisible_) * lineDepth_;
00425         }
00426 
00427         // Skip the lines we are not viewing
00428         // (Should make this more efficient)
00429         std::list<GLWChannelViewEntry>::iterator startingPos = textLines_.begin();
00430         {
00431                 int count = 0;
00432                 for (;
00433                         startingPos != textLines_.end() && count < scrollPosition_;
00434                         startingPos++, count++)
00435                 {
00436                 }
00437         }
00438 
00439         // Draw all the black outlines first
00440         // Do this in a block incase any of the outlines would over write any
00441         // of the other lines
00442         {
00443                 int count = 0;
00444                 std::list<GLWChannelViewEntry>::iterator itor;
00445                 for (itor = startingPos;
00446                         itor != textLines_.end() && count < visibleLines_;
00447                         itor++, count++)
00448                 {
00449                         GLWChannelViewEntry &entry = (*itor);
00450 
00451                         float alpha = 1.0f;
00452                         if (scrollPosition_ < 0)
00453                         {
00454                                 if (entry.timeRemaining <= 0.0f) continue;
00455                                 if (entry.timeRemaining < 1.0f) alpha = entry.timeRemaining;
00456                         }
00457 
00458                         float x = x_ + 20.0f;
00459                         float y = start + count * lineDepth_;
00460 
00461                         GLWFont::instance()->getGameShadowFont()->
00462                                 drawA(GLWColors::black, alpha, fontSize_,
00463                                         x - 1.0f, y + 1.0f, 0.0f, 
00464                                         entry.text.getString());
00465                 }
00466         }
00467         // Draw the actual text
00468         {
00469                 int count = 0;
00470                 std::list<GLWChannelViewEntry>::iterator itor;
00471                 for (itor = startingPos;
00472                         itor != textLines_.end() && count < visibleLines_;
00473                         itor++, count++)
00474                 {
00475                         GLWChannelViewEntry &entry = (*itor);
00476 
00477                         float alpha = 1.0f;
00478                         if (scrollPosition_ < 0)
00479                         {
00480                                 if (entry.timeRemaining <= 0.0f) continue;
00481                                 if (entry.timeRemaining < 1.0f) alpha = entry.timeRemaining;
00482                         }
00483 
00484                         float x = x_ + 20.0f;
00485                         float y = start + count * lineDepth_;
00486 
00487                         GLWFont::instance()->getGameFont()->
00488                                 drawA(&entry.text, entry.color, alpha, fontSize_,
00489                                         x, y, 0.0f, 
00490                                         entry.text.getString());
00491                 }
00492         }
00493 }
00494 
00495 void GLWChannelView::mouseDown(int button, float x, float y, bool &skipRest)
00496 {
00497         skipRest = false;
00498         upButton_.mouseDown(button, x, y, skipRest);
00499         downButton_.mouseDown(button, x, y, skipRest);
00500         resetButton_.mouseDown(button, x, y, skipRest);
00501 }
00502 
00503 void GLWChannelView::mouseUp(int button, float x, float y, bool &skipRest)
00504 {
00505         skipRest = false;
00506         upButton_.mouseUp(button, x, y, skipRest);
00507         downButton_.mouseUp(button, x, y, skipRest);
00508         resetButton_.mouseUp(button, x, y, skipRest);
00509 }
00510 
00511 void GLWChannelView::mouseDrag(int button, float mx, float my, float x, float y, bool &skipRest)
00512 {
00513         skipRest = false;
00514         upButton_.mouseDrag(button, mx, my, x, y, skipRest);
00515         downButton_.mouseDrag(button, mx, my, x, y, skipRest);
00516         resetButton_.mouseDrag(button, mx, my, x, y, skipRest);
00517 }
00518 
00519 void GLWChannelView::keyDown(char *buffer, unsigned int keyState, 
00520         KeyboardHistory::HistoryElement *history, int hisCount, 
00521         bool &skipRest)
00522 {
00523         if (scrollUpKey_ && scrollUpKey_->keyDown(buffer, keyState, false))
00524         {
00525                 buttonDown(upButton_.getId());
00526                 skipRest = true;
00527         }
00528         if (scrollDownKey_ && scrollDownKey_->keyDown(buffer, keyState, false))
00529         {
00530                 buttonDown(downButton_.getId());
00531                 skipRest = true;
00532         }
00533         if (scrollResetKey_ && scrollResetKey_->keyDown(buffer, keyState, false))
00534         {
00535                 buttonDown(resetButton_.getId());
00536                 skipRest = true;
00537         }
00538 }
00539 
00540 bool GLWChannelView::initFromXML(XMLNode *node)
00541 {
00542         if (!GLWidget::initFromXML(node)) return false;
00543 
00544         if (!initFromXMLInternal(node)) return false;
00545                 
00546         return true;
00547 }
00548 
00549 void GLWChannelView::formCurrentChannelList(std::list<std::string> &result)
00550 {
00551         std::list<CurrentChannelEntry>::iterator itor;
00552         for (itor = currentChannels_.begin();
00553                 itor != currentChannels_.end();
00554                 itor++)
00555         {
00556                 CurrentChannelEntry &entry = *itor;
00557                 result.push_back(entry.channel);
00558         }
00559 }
00560 
00561 bool GLWChannelView::initFromXMLInternal(XMLNode *node)
00562 {
00563         if (!node->getNamedChild("displaytime", displayTime_)) return false;
00564         if (!node->getNamedChild("totallines", totalLines_)) return false;
00565         if (!node->getNamedChild("visiblelines", visibleLines_)) return false;
00566         if (!node->getNamedChild("linedepth", lineDepth_)) return false;
00567         if (!node->getNamedChild("fontsize", fontSize_)) return false;
00568         if (!node->getNamedChild("outlinefontsize", outlineFontSize_)) return false;
00569         if (!node->getNamedChild("textaligntop", alignTop_)) return false;
00570         if (!node->getNamedChild("parentsized", parentSized_)) return false;
00571         if (!node->getNamedChild("splitlargelines", splitLargeLines_)) return false;
00572         if (!node->getNamedChild("allowscroll", allowScroll_)) return false;
00573         if (!node->getNamedChild("showchannelname", showChannelName_)) return false;
00574         if (!node->getNamedChild("showchannelnumber", showChannelNumber_)) return false;
00575         
00576         node->getNamedChild("textsound", textSound_, false);
00577 
00578         std::string startupchannel;
00579         while (node->getNamedChild("channel", startupchannel, false))
00580         {
00581                 startupChannels_.push_back(startupchannel);
00582         }
00583 
00584         XMLNode *channelcolors;
00585         while (node->getNamedChild("channelcolor", channelcolors, false))
00586         {
00587                 std::string channel;
00588                 Vector color;
00589                 if (!channelcolors->getNamedChild("channel", channel)) return false;
00590                 if (!channelcolors->getNamedChild("color", color)) return false;
00591                 channelColors_[channel] = color;
00592         }
00593 
00594         std::string scrollUpKey, scrollDownKey, scrollResetKey;
00595         if (node->getNamedChild("scrollupkey", scrollUpKey, false))
00596         {
00597                 scrollUpKey_ = Keyboard::instance()->getKey(scrollUpKey.c_str());
00598         }
00599         if (node->getNamedChild("scrolldownkey", scrollDownKey, false))
00600         {
00601                 scrollDownKey_ = Keyboard::instance()->getKey(scrollDownKey.c_str());
00602         }
00603         if (node->getNamedChild("scrollresetkey", scrollResetKey, false))
00604         {
00605                 scrollResetKey_ = Keyboard::instance()->getKey(scrollResetKey.c_str());
00606         }
00607         return true;
00608 }

Generated on Mon Feb 16 15:14:45 2009 for Scorched3D by  doxygen 1.5.3