GLWListView.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/GLWListView.h>
00022 #include <GLW/GLWFont.h>
00023 #include <GLW/GLWTranslate.h>
00024 #include <common/Defines.h>
00025 #include <client/ScorchedClient.h>
00026 #include <engine/GameState.h>
00027 #include <stdio.h>
00028 
00029 static const float BorderWidth = 20.0f;
00030 
00031 REGISTER_CLASS_SOURCE(GLWListView);
00032 
00033 unsigned GLWListView::WordEntry::wordRefCount_ = 1;
00034 
00035 GLWListView::GLWListView(float x, float y, float w, float h, 
00036         int maxLen, float textSize, float scrollSpeed) :
00037         GLWidget(x, y, w, h), 
00038         scroll_(x + w - 17, y, h - 1, 0, 1), 
00039         maxLen_(maxLen), textSize_(textSize),
00040         scrollSpeed_(scrollSpeed),
00041         handler_(0), currentPosition_(0.0f)
00042 {
00043         color_ = GLWFont::widgetFontColor;
00044         scroll_.setMax((int) lines_.size());
00045         scroll_.setSee((int) (h_ / 12.0f));
00046         scroll_.setCurrent(scroll_.getMax());
00047 }
00048 
00049 GLWListView::~GLWListView()
00050 {
00051 }
00052 
00053 void GLWListView::draw()
00054 {
00055         glBegin(GL_LINE_LOOP);
00056                 drawShadedRoundBox(x_, y_, w_, h_, 6.0f, false);
00057         glEnd();
00058 
00059         {
00060                 // Stops each font draw from changing state every time
00061                 GLState currentState(GLState::TEXTURE_ON | GLState::BLEND_ON);
00062                 GLFont2d *font = GLWFont::instance()->getGameFont();
00063 
00064                 // Clear the currently stored urls
00065                 urls_.clear();
00066 
00067                 // Calculate current position
00068                 float posY = y_ + h_ - (textSize_ + 4.0f);
00069                 int pos = (scroll_.getMax() - scroll_.getSee()) - scroll_.getCurrent();
00070 
00071                 // Figure out how many characters we are not drawing because
00072                 // they are off the top of the scrolling window
00073                 int charCount = 0;
00074                 for (int i=0; i<pos; i++)
00075                 {
00076                         LineEntry &lineEntry = lines_[i];
00077 
00078                         for (int j=0; j<(int) lineEntry.words_.size(); j++)
00079                         {
00080                                 WordEntry &wordEntry = lineEntry.words_[j];
00081                                 charCount += (int) wordEntry.word_.size();
00082                         }
00083                 }
00084 
00085                 // For each line
00086                 bool newWords = false;
00087                 for (int i=pos; i<(int) scroll_.getMax(); i++)
00088                 {
00089                         // Check the line is valid
00090                         if (i >= 0 && i < (int) lines_.size())
00091                         {
00092                                 float width = w_ - BorderWidth;
00093                                 float widthUsed = 0.0f;
00094 
00095                                 // For each word
00096                                 LineEntry &lineEntry = lines_[i];
00097                                 for (int j=0; j<(int) lineEntry.words_.size(); j++)
00098                                 {
00099                                         WordEntry &wordEntry = lineEntry.words_[j];
00100 
00101                                         // Check if there is space left to draw this word
00102                                         int possibleChars = font->getChars(textSize_, wordEntry.word_.c_str(), width - widthUsed);
00103                                         int drawChars = possibleChars;
00104                                         if (scrollSpeed_ > 0.0f)
00105                                         {
00106                                                 if (possibleChars + charCount > (int) currentPosition_)
00107                                                 {
00108                                                         drawChars = int(currentPosition_) - charCount;
00109                                                 }
00110                                         }
00111 
00112                                         if (drawChars > 0)
00113                                         {
00114                                                 // Draw this word
00115                                                 font->drawSubStr(0, drawChars,
00116                                                         wordEntry.color_,
00117                                                         textSize_,
00118                                                         x_ + 5.0f + widthUsed, posY, 0.0f, 
00119                                                         S3D::formatStringBuffer("%s", wordEntry.word_.c_str()));
00120 
00121                                                 // Send the event (if any)
00122                                                 if (wordEntry.wordRef_ != wordEntry.wordRefCount_)
00123                                                 {
00124                                                         newWords = true;
00125                                                         wordEntry.wordRef_ = wordEntry.wordRefCount_;
00126                                                         if (!wordEntry.event_.empty() && handler_)
00127                                                         {
00128                                                                 handler_->event(wordEntry.event_);
00129                                                         }
00130                                                 }
00131 
00132                                                 // Draw the url (if any)
00133                                                 if (wordEntry.href_.size() > 0)
00134                                                 {
00135                                                         drawUrl(wordEntry, drawChars, widthUsed, posY);
00136                                                 }
00137                                         }
00138 
00139                                         // Add this word to the space used
00140                                         float wordWidth = font->getWidth(
00141                                                 textSize_, wordEntry.word_.c_str());
00142                                         widthUsed += wordWidth;
00143                                         charCount += (int) wordEntry.word_.size();
00144                                 }
00145 
00146                                 // Move down a line
00147                                 posY -= (textSize_ + 2.0f);
00148                         }
00149 
00150                         // Check if we should scroll down
00151                         if (posY < y_) 
00152                         {
00153                                 if (scrollSpeed_ > 0.0f && newWords)
00154                                 {
00155                                         scroll_.setCurrent(scroll_.getCurrent() - 1);
00156                                 }
00157                                 break;
00158                         }
00159 
00160                         // Check if we have drawn more than we should see
00161                         if ((scrollSpeed_ > 0.0f) && (charCount > int(currentPosition_))) break;
00162                 }
00163         }
00164 
00165         scroll_.draw();
00166 }
00167 
00168 void GLWListView::simulate(float frameTime)
00169 {
00170         currentPosition_ += (frameTime * scrollSpeed_);
00171         scroll_.simulate(frameTime);
00172 }
00173 
00174 void GLWListView::mouseDown(int button, float x, float y, bool &skipRest)
00175 {
00176         std::vector<UrlEntry>::iterator itor;
00177         for (itor = urls_.begin();
00178                 itor != urls_.end();
00179                 itor++)
00180         {
00181                 UrlEntry &entry = *itor;
00182                 if (inBox(x, y, entry.x_, entry.y_, entry.w_, entry.h_))
00183                 {
00184                         if (handler_)
00185                         {
00186                                 const char *url = entry.entry_->href_.c_str();
00187                                 handler_->url(url);
00188                         }
00189                         skipRest = true;
00190                         return;
00191                 }
00192         }
00193 
00194         scroll_.mouseDown(button, x, y, skipRest);
00195 }
00196 
00197 void GLWListView::mouseUp(int button, float x, float y, bool &skipRest)
00198 {
00199         scroll_.mouseUp(button, x, y, skipRest);
00200 }
00201 
00202 void GLWListView::mouseDrag(int button, float mx, float my, float x, float y, bool &skipRest)
00203 {
00204         scroll_.mouseDrag(button, mx, my, x, y, skipRest);
00205 }
00206 
00207 void GLWListView::mouseWheel(float x, float y, float z, bool &skipRest)
00208 {
00209         if (inBox(x, y, x_, y_, w_, h_))
00210         {
00211                 skipRest = true;
00212 
00213                 if (z < 0.0f) scroll_.setCurrent(scroll_.getCurrent() + 1);
00214                 else scroll_.setCurrent(scroll_.getCurrent() - 1);
00215         }
00216 }
00217 
00218 void GLWListView::clear()
00219 {
00220         lines_.clear();
00221         scroll_.setCurrent(0);
00222         resetPosition();
00223 }
00224 
00225 void GLWListView::endPosition()
00226 {
00227         scroll_.setCurrent(scroll_.getMin());
00228 }
00229 
00230 void GLWListView::resetPosition()
00231 {
00232         GLWListView::WordEntry::wordRefCount_++;
00233         currentPosition_ = 0.0f;
00234 }
00235 
00236 bool GLWListView::addWordEntry(std::list<WordEntry> &words,
00237         std::string &word, XMLNode *parentNode)
00238 {
00239         WordEntry wordEntry(word.c_str(), color_);
00240         word = "";
00241 
00242         if (0 == strcmp("event", parentNode->getName()))
00243         {
00244                 wordEntry.color_ = Vector(0.4f, 0.0f, 0.0f);
00245 
00246                 std::list<XMLNode *> &parameters = parentNode->getParameters();
00247                 std::list<XMLNode *>::iterator itor;
00248                 for (itor = parameters.begin();
00249                         itor != parameters.end();
00250                         itor++)
00251                 {
00252                         XMLNode *node = *itor;
00253                         wordEntry.event_[node->getName()] = node->getContent();
00254                 }
00255         } 
00256         else if (0 == strcmp("a", parentNode->getName()))
00257         {
00258                 wordEntry.color_ = Vector(0.4f, 0.0f, 0.0f);
00259                 if (!parentNode->getNamedParameter("href", wordEntry.href_, true, false))
00260                 {
00261                         return false;
00262                 }
00263         }
00264 
00265         words.push_back(wordEntry);
00266         return true;
00267 }
00268 
00269 bool GLWListView::getLines(std::list<WordEntry> &words, float &lineLen)
00270 {
00271         std::list<WordEntry>::iterator itor;
00272         for (itor = words.begin();
00273                 itor != words.end();
00274                 itor++)
00275         {
00276                 WordEntry &wordEntry = *itor;
00277 
00278                 if (wordEntry.word_.c_str()[0] == '\n')
00279                 {
00280                         // Add a new line
00281                         LineEntry lineEntry;
00282                         lines_.push_back(lineEntry);
00283                         lineLen = 0.0f;
00284                 }
00285                 else
00286                 {
00287                         // Check if weve run out of space on the current line
00288                         float wordLen = 
00289                                 GLWFont::instance()->getGameFont()->
00290                                 getWidth(textSize_, wordEntry.word_.c_str());
00291                         if (wordLen + lineLen >= w_ - BorderWidth)
00292                         {
00293                                 // Add a new line
00294                                 LineEntry lineEntry;
00295                                 lines_.push_back(lineEntry);
00296                                 lineLen = 0.0f;
00297                         }
00298                 
00299                         lines_.back().words_.push_back(wordEntry);
00300                         lineLen += wordLen;
00301                 }
00302         }
00303 
00304         return true;
00305 }
00306 
00307 bool GLWListView::getWords(XMLNode *node, std::list<WordEntry> &words)
00308 {
00309         // For each child XML node
00310         std::list<XMLNode *>::iterator childrenItor;
00311         std::list<XMLNode *> children = node->getChildren();
00312         for (childrenItor = children.begin();
00313                 childrenItor != children.end();
00314                 childrenItor++)
00315         {
00316                 XMLNode *child = (*childrenItor);
00317 
00318                 // Get the child node type
00319                 if (child->getType() == XMLNode::XMLNodeType)
00320                 {
00321                         // Its another node, recurse over its children too
00322                         if (!getWords(child, words)) return false;
00323                 }
00324                 else
00325                 {
00326                         // Its a text type, add the words from the text
00327                         std::string word;
00328                         for (const char *t=child->getContent(); *t; t++)
00329                         {
00330                                 if (*t == '\n')
00331                                 {
00332                                         // Add the current word
00333                                         if (!addWordEntry(words, word, node)) return false;
00334 
00335                                         word = "\n";
00336                                         if (!addWordEntry(words, word, node)) return false;
00337                                 }
00338                                 else
00339                                 {
00340                                         word += *t;
00341 
00342                                         // A word break
00343                                         if (*t == ' ')
00344                                         {
00345                                                 // Add a new word
00346                                                 if (!addWordEntry(words, word, node)) return false;
00347                                         }
00348                                 }
00349                         }
00350 
00351                         // Add any words we've got left over
00352                         if (!addWordEntry(words, word, node)) return false;
00353                 }
00354         }
00355 
00356         return true;
00357 }
00358 
00359 bool GLWListView::addXML(XMLNode *node)
00360 {
00361         // Recurse over the document adding the words
00362         std::list<WordEntry> words;
00363         if (!getWords(node, words)) return false;
00364 
00365         // Add a blank line to start with
00366         LineEntry lineEntry;
00367         lines_.push_back(lineEntry);
00368         float lineLen = 0.0f;
00369         getLines(words, lineLen);
00370 
00371         // Setup the current scroll position
00372         setScroll();
00373 
00374         return true;
00375 }
00376 
00377 void GLWListView::addLine(const std::string &text)
00378 {
00379         // Remove extra lines
00380         if (maxLen_ > 0)
00381         {
00382                 if (lines_.size() > (unsigned int) maxLen_) lines_.clear();
00383         }
00384 
00385         // Generate the line to add (add a single word)
00386         WordEntry wordEntry(text.c_str(), color_);
00387         LineEntry lineEntry;
00388         lineEntry.words_.push_back(wordEntry);
00389         lines_.push_back(lineEntry);
00390 
00391         // Setup the current scroll position
00392         setScroll();
00393 }
00394 
00395 void GLWListView::setScroll()
00396 {
00397         int view = (int) (h_ / (textSize_ + 2.0f));
00398         scroll_.setMax((int) lines_.size());
00399         scroll_.setSee(view);
00400         scroll_.setCurrent(scroll_.getMax() - scroll_.getSee());
00401 }
00402 
00403 void GLWListView::drawUrl(WordEntry &wordEntry, int drawChars, float x, float y)
00404 {
00405         GLFont2d *font = GLWFont::instance()->getGameFont();
00406         float partWordWidth = font->getWidth(
00407                 textSize_, wordEntry.word_.c_str(), drawChars);
00408 
00409         // Add the new url entry
00410         UrlEntry urlEntry;
00411         urlEntry.x_ = x_ + 5.0f + x;
00412         urlEntry.y_ = y - 2.0f;
00413         urlEntry.w_ = partWordWidth;
00414         urlEntry.h_ = textSize_ + 2.0f;
00415         urlEntry.entry_ = &wordEntry;
00416         urls_.push_back(urlEntry);
00417 
00418         // Draw the underline
00419         GLState noTexState(GLState::TEXTURE_OFF);
00420         glLineWidth(2.0f);
00421         glColor3fv(wordEntry.color_);
00422         glBegin(GL_LINES);
00423                 glVertex2f(x_ + 5.0f + x, y - 2.0f);
00424                 glVertex2f(x_ + 5.0f + x + partWordWidth, y - 2.0f);
00425         glEnd();
00426         glLineWidth(1.0f);
00427 }

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