Main Page | Class Hierarchy | Class List | Directories | File List | Class Members | Related Pages

textbox.cpp

00001 /*      _______   __   __   __   ______   __   __   _______   __   __                 
00002  *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\                
00003  *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /                 
00004  *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /                  
00005  *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /                   
00006  * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /                    
00007  * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/                      
00008  *
00009  * Copyright (c) 2004, 2005 darkbits                        Js_./
00010  * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
00011  * Olof Naessén a.k.a jansem/yakslem                _asww7!uY`>  )\a//
00012  *                                                 _Qhm`] _f "'c  1!5m
00013  * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
00014  *                                               .)j(] .d_/ '-(  P .   S
00015  * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
00016  * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
00017  * binary forms, with or without                 )4d[#7r, .   '     )d`)[
00018  * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
00019  * that the following conditions are met:       j<<WP+k/);.        _W=j f
00020  * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
00021  *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
00022  *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
00023  *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
00024  * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
00025  *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
00026  *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
00027  *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
00028  *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
00029  *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
00030  * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
00031  *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
00032  *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
00033  *    from this software without specific        (js, \[QQW$QWW#?!V"".
00034  *    prior written permission.                    ]y:.<\..          .
00035  *                                                 -]n w/ '         [.
00036  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
00037  * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
00038  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
00039  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
00040  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
00041  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
00042  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
00043  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
00044  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
00045  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
00046  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
00047  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
00048  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00049  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00050  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00051  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00052  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00053  */
00054 
00055 /*
00056  * For comments regarding functions please see the header file. 
00057  */
00058 
00059 #include <typeinfo>
00060 
00061 #include "guichan/basiccontainer.hpp"
00062 #include "guichan/keyinput.hpp"
00063 #include "guichan/mouseinput.hpp"
00064 #include "guichan/widgets/scrollarea.hpp"
00065 #include "guichan/widgets/textbox.hpp"
00066 
00067 namespace gcn
00068 {
00069     TextBox::TextBox()
00070     {
00071         mCaretColumn = 0;
00072         mCaretRow = 0;
00073         mEditable = true;
00074         mOpaque = true;
00075         
00076         setFocusable(true);
00077     
00078         addMouseListener(this);
00079         addKeyListener(this);
00080         adjustSize();
00081         setBorderSize(1);    
00082     }
00083   
00084     TextBox::TextBox(const std::string& text)
00085     {
00086         mCaretColumn = 0;
00087         mCaretRow = 0;
00088         mEditable = true;
00089         mOpaque = true;
00090         
00091         setText(text);
00092     
00093         setFocusable(true);    
00094     
00095         addMouseListener(this);
00096         addKeyListener(this);
00097         adjustSize();
00098         setBorderSize(1);    
00099     }
00100 
00101     void TextBox::setText(const std::string& text)
00102     {
00103         mCaretColumn = 0;
00104         mCaretRow = 0;
00105 
00106         mTextRows.clear();
00107     
00108         std::string::size_type pos, lastPos = 0;
00109         int length;
00110         do
00111         {
00112             pos = text.find("\n", lastPos);
00113 
00114             if (pos != std::string::npos)
00115             {
00116                 length = pos - lastPos;
00117             }
00118             else
00119             {
00120                 length = text.size() - lastPos;
00121             }
00122             std::string sub = text.substr(lastPos, length);
00123             mTextRows.push_back(sub);
00124             lastPos = pos + 1;
00125       
00126         } while (pos != std::string::npos);
00127 
00128         adjustSize();    
00129     }
00130   
00131     void TextBox::draw(Graphics* graphics)
00132     {
00133         unsigned int i;
00134 
00135         if (mOpaque)
00136         {            
00137             graphics->setColor(getBackgroundColor());    
00138             graphics->fillRectangle(Rectangle(0, 0, getWidth(), getHeight()));
00139         }
00140         
00141         if (hasFocus() && isEditable())
00142         {      
00143             drawCaret(graphics, getFont()->getWidth(mTextRows[mCaretRow].substr(0, mCaretColumn)), mCaretRow * getFont()->getHeight());
00144         }
00145     
00146         graphics->setColor(getForegroundColor());
00147         graphics->setFont(getFont());
00148 
00149         for (i = 0; i < mTextRows.size(); i++)
00150         {
00151             // Move the text one pixel so we can have a caret before a letter.
00152             graphics->drawText(mTextRows[i], 1, i * getFont()->getHeight());
00153         }    
00154     }
00155 
00156     void TextBox::drawBorder(Graphics* graphics)
00157     {
00158         int width = getWidth() + getBorderSize() * 2 - 1;
00159         int height = getHeight() + getBorderSize() * 2 - 1;
00160 
00161         graphics->setColor(getBackgroundColor());
00162 
00163         unsigned int i;
00164         for (i = 0; i < getBorderSize(); ++i)
00165         {
00166             graphics->drawLine(i,i, width - i, i);
00167             graphics->drawLine(i,i + 1, i, height - i - 1);
00168             graphics->drawLine(width - i,i + 1, width - i, height - i); 
00169             graphics->drawLine(i,height - i, width - i - 1, height - i);
00170         }
00171     }
00172     
00173     void TextBox::drawCaret(Graphics* graphics, int x, int y)
00174     {
00175         graphics->setColor(getForegroundColor());
00176         graphics->drawLine(x, getFont()->getHeight() + y, x, y);
00177     }
00178   
00179     void TextBox::mousePress(int x, int y, int button)
00180     {        
00181         if (hasMouse() && button == MouseInput::LEFT)
00182         {
00183             mCaretRow = y / getFont()->getHeight();
00184 
00185             if (mCaretRow >= (int)mTextRows.size())
00186             {
00187                 mCaretRow = mTextRows.size() - 1;
00188             }
00189       
00190             mCaretColumn = getFont()->getStringIndexAt(mTextRows[mCaretRow], x);
00191         }
00192     }
00193   
00194     void TextBox::keyPress(const Key& key)
00195     {    
00196         if (key.getValue() == Key::LEFT)
00197         {
00198             --mCaretColumn;
00199             if (mCaretColumn < 0)
00200             {
00201                 --mCaretRow;
00202 
00203                 if (mCaretRow < 0)
00204                 {
00205                     mCaretRow = 0;
00206                     mCaretColumn = 0;
00207                 }
00208                 else
00209                 {
00210                     mCaretColumn = mTextRows[mCaretRow].size();
00211                 }
00212             }
00213         }
00214 
00215         else if (key.getValue() == Key::RIGHT)
00216         {
00217             ++mCaretColumn;
00218             if (mCaretColumn > (int)mTextRows[mCaretRow].size())
00219             {
00220                 ++mCaretRow;
00221 
00222                 if (mCaretRow >= (int)mTextRows.size())
00223                 {
00224                     mCaretRow = mTextRows.size() - 1;
00225                     if (mCaretRow < 0)
00226                     {
00227                         mCaretRow = 0;
00228                     }
00229           
00230                     mCaretColumn = mTextRows[mCaretRow].size();
00231                 }
00232                 else
00233                 {
00234                     mCaretColumn = 0;
00235                 }
00236             }
00237         }
00238 
00239         else if (key.getValue() == Key::DOWN)
00240         {
00241             setCaretRow(mCaretRow + 1);
00242         }
00243 
00244         else if (key.getValue() == Key::UP)
00245         {
00246             setCaretRow(mCaretRow - 1);
00247         }
00248 
00249         else if (key.getValue() == Key::HOME)
00250         {
00251             mCaretColumn = 0;
00252         }    
00253 
00254         else if (key.getValue() == Key::END)
00255         {
00256             mCaretColumn = mTextRows[mCaretRow].size();
00257         }    
00258 
00259         else if (key.getValue() == Key::ENTER && mEditable)
00260         {
00261             mTextRows.insert(mTextRows.begin() + mCaretRow + 1,
00262                              mTextRows[mCaretRow].substr(mCaretColumn, mTextRows[mCaretRow].size() - mCaretColumn));
00263             mTextRows[mCaretRow].resize(mCaretColumn);
00264             ++mCaretRow;
00265             mCaretColumn = 0;
00266         }
00267 
00268         else if (key.getValue() == Key::BACKSPACE
00269                  && mCaretColumn != 0
00270                  && mEditable)
00271         {
00272             mTextRows[mCaretRow].erase(mCaretColumn - 1, 1);
00273             --mCaretColumn;
00274         }
00275 
00276         else if (key.getValue() == Key::BACKSPACE
00277                  && mCaretColumn == 0
00278                  && mCaretRow != 0
00279                  && mEditable)
00280         {
00281             mCaretColumn = mTextRows[mCaretRow - 1].size();
00282             mTextRows[mCaretRow - 1] += mTextRows[mCaretRow];
00283             mTextRows.erase(mTextRows.begin() + mCaretRow);
00284             --mCaretRow;
00285         }
00286 
00287         else if (key.getValue() == Key::DELETE
00288                  && mCaretColumn < (int)mTextRows[mCaretRow].size()
00289                  && mEditable)
00290         {
00291             mTextRows[mCaretRow].erase(mCaretColumn, 1);
00292         }
00293 
00294         else if (key.getValue() == Key::DELETE
00295                  && mCaretColumn == (int)mTextRows[mCaretRow].size()
00296                  && mCaretRow < ((int)mTextRows.size() - 1)
00297                  && mEditable)
00298         {
00299             mTextRows[mCaretRow] += mTextRows[mCaretRow + 1];
00300             mTextRows.erase(mTextRows.begin() + mCaretRow + 1);
00301         }
00302 
00303         else if(key.getValue() == Key::PAGE_UP)
00304         {
00305             int w, h, rowsPerPage;
00306             getParent()->getDrawSize(w, h, this);
00307             rowsPerPage = h / getFont()->getHeight();
00308             mCaretRow -= rowsPerPage;
00309 
00310             if (mCaretRow < 0)
00311             {
00312                 mCaretRow = 0;
00313             }
00314         }
00315 
00316         else if(key.getValue() == Key::PAGE_DOWN)
00317         {
00318             int w, h, rowsPerPage;
00319             getParent()->getDrawSize(w, h, this);
00320             rowsPerPage = h / getFont()->getHeight();
00321             mCaretRow += rowsPerPage;
00322 
00323             if (mCaretRow >= (int)mTextRows.size())
00324             {
00325                 mCaretRow = mTextRows.size() - 1;
00326             }
00327         }
00328 
00329         else if(key.getValue() == Key::TAB
00330                 && mEditable)
00331         {
00332             mTextRows[mCaretRow].insert(mCaretColumn,std::string("    "));
00333             mCaretColumn += 4;      
00334         }
00335 
00336         else if (key.isCharacter()
00337                  && mEditable)
00338         {
00339             mTextRows[mCaretRow].insert(mCaretColumn,std::string(1,(char)key.getValue()));
00340             ++mCaretColumn;
00341         }   
00342    
00343         adjustSize();
00344         scrollToCaret();    
00345     }
00346 
00347     void TextBox::adjustSize()
00348     {
00349         unsigned int i;
00350         int width = 0;
00351         for (i = 0; i < mTextRows.size(); ++i)
00352         {
00353             int w = getFont()->getWidth(mTextRows[i]);
00354             if (width < w)
00355             {
00356                 width = w;
00357             }
00358         }
00359            
00360         setWidth(width + 1);
00361         setHeight(getFont()->getHeight() * mTextRows.size());
00362     } 
00363   
00364     void TextBox::setCaretPosition(unsigned int position)
00365     {
00366         int row;
00367 
00368         for (row = 0; row < (int)mTextRows.size(); row++)
00369         {
00370             if (position <= mTextRows[row].size())
00371             {
00372                 mCaretRow = row;
00373                 mCaretColumn = position;
00374                 return; // we are done
00375             }
00376             else
00377             {
00378                 position--;        
00379             }
00380         }
00381 
00382         // position beyond end of text
00383         mCaretRow = mTextRows.size() - 1;
00384         mCaretColumn = mTextRows[mCaretRow].size();    
00385     }
00386 
00387     unsigned int TextBox::getCaretPosition() const
00388     {
00389         int pos = 0, row;
00390 
00391         for (row = 0; row < mCaretRow; row++)
00392         {
00393             pos += mTextRows[row].size();
00394         }
00395 
00396         return pos + mCaretColumn;    
00397     }
00398 
00399     void TextBox::setCaretRowColumn(int row, int column)
00400     {
00401         setCaretRow(row);
00402         setCaretColumn(column);
00403     }
00404 
00405     void TextBox::setCaretRow(int row)
00406     {    
00407         mCaretRow = row;
00408 
00409         if (mCaretRow >= (int)mTextRows.size())
00410         {
00411             mCaretRow = mTextRows.size() - 1;
00412         }
00413 
00414         if (mCaretRow < 0)
00415         {
00416             mCaretRow = 0;
00417         }
00418 
00419         setCaretColumn(mCaretColumn);    
00420     }
00421   
00422     unsigned int TextBox::getCaretRow() const
00423     {
00424         return mCaretRow;    
00425     }
00426 
00427     void TextBox::setCaretColumn(int column)
00428     {
00429         mCaretColumn = column;
00430 
00431         if (mCaretColumn > (int)mTextRows[mCaretRow].size())
00432         {
00433             mCaretColumn = mTextRows[mCaretRow].size();
00434         }
00435 
00436         if (mCaretColumn < 0)
00437         {
00438             mCaretColumn = 0;
00439         }
00440     }
00441 
00442     unsigned int TextBox::getCaretColumn() const
00443     {
00444         return mCaretColumn;
00445     }
00446   
00447     const std::string& TextBox::getTextRow(int row) const
00448     {
00449         return mTextRows[row];
00450     }
00451 
00452     void TextBox::setTextRow(int row, const std::string& text)
00453     {
00454         mTextRows[row] = text;
00455 
00456         if (mCaretRow == row)
00457         {
00458             setCaretColumn(mCaretColumn);
00459         }
00460 
00461         adjustSize();
00462     }
00463 
00464     unsigned int TextBox::getNumberOfRows() const
00465     {
00466         return mTextRows.size();
00467     }
00468 
00469     std::string TextBox::getText() const
00470     {
00471         if (mTextRows.size() == 0)
00472         {
00473             return std::string("");
00474         }
00475     
00476         int i;
00477         std::string text;
00478     
00479         for (i = 0; i < (int)mTextRows.size() - 1; ++i)
00480         {
00481             text = text + mTextRows[i] + "\n";
00482         }
00483 
00484         text = text + mTextRows[i];
00485 
00486         return text;
00487     }
00488 
00489     void TextBox::fontChanged()
00490     {
00491         adjustSize();
00492     }
00493 
00494     void TextBox::scrollToCaret()
00495     {
00496         Widget *par = getParent();
00497         if (par == NULL)
00498         {
00499             return;
00500         }            
00501         
00502         ScrollArea* scrollArea = dynamic_cast<ScrollArea *>(par);
00503         if (scrollArea != NULL)
00504         {
00505             Rectangle scroll;
00506             scroll.x = getFont()->getWidth(mTextRows[mCaretRow].substr(0, mCaretColumn));
00507             scroll.y = getFont()->getHeight() * mCaretRow;
00508             scroll.width = 6;
00509             scroll.height = getFont()->getHeight() + 2; // add 2 for some extra space
00510             scrollArea->scrollToRectangle(scroll);
00511         }
00512     }
00513 
00514     void TextBox::setEditable(bool editable)
00515     {
00516         mEditable = editable;
00517     }
00518 
00519     bool TextBox::isEditable() const
00520     {
00521         return mEditable;
00522     }
00523 
00524     void TextBox::addRow(const std::string row)
00525     {
00526         mTextRows.push_back(row);
00527         adjustSize();
00528     }
00529 
00530     bool TextBox::isOpaque()
00531     {
00532         return mOpaque;
00533     }
00534 
00535     void TextBox::setOpaque(bool opaque)
00536     {
00537         mOpaque = opaque;
00538     }    
00539 }

Generated on Tue May 17 21:23:26 2005 for Guichan by  doxygen 1.4.1