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

dropdown.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 #include "guichan/exception.hpp"
00056 #include "guichan/widgets/dropdown.hpp"
00057 
00058 namespace gcn
00059 {  
00060     DropDown::DropDown()
00061     {
00062         mDroppedDown = false;
00063         mPushed = false;
00064     
00065         setWidth(100);
00066         setFocusable(true);
00067 
00068         mDefaultScrollArea = new ScrollArea();
00069         mDefaultScrollArea->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER);
00070         mDefaultListBox = new ListBox();
00071 
00072         mScrollArea = mDefaultScrollArea;
00073         mScrollArea->_setFocusHandler(&mFocusHandler);
00074         mScrollArea->_setParent(this);
00075         
00076         mListBox = mDefaultListBox;    
00077         mListBox->addActionListener(this);
00078         mScrollArea->setContent(mListBox);
00079         
00080         addMouseListener(this);
00081         addKeyListener(this);
00082         adjustHeight();
00083         setBorderSize(1);        
00084     }
00085     
00086     DropDown::DropDown(ListModel *listModel)
00087     {
00088         setWidth(100);
00089         setFocusable(true);
00090         mDroppedDown = false;
00091         mPushed = false;    
00092     
00093         mDefaultScrollArea = new ScrollArea();
00094         mDefaultScrollArea->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER);
00095         mDefaultListBox = new ListBox();
00096 
00097         mScrollArea = mDefaultScrollArea;
00098         mScrollArea->_setParent(this);
00099         mListBox = mDefaultListBox;
00100         mListBox->addActionListener(this);
00101             
00102         mScrollArea->setContent(mListBox);
00103         mScrollArea->_setFocusHandler(&mFocusHandler);
00104         mScrollArea->_setParent(this);
00105             
00106         setListModel(listModel);
00107     
00108         if (mListBox->getSelected() < 0)
00109         {
00110             mListBox->setSelected(0);
00111         }
00112 
00113         addMouseListener(this);
00114         addKeyListener(this);
00115         adjustHeight();
00116         setBorderSize(1);        
00117     }
00118   
00119     DropDown::DropDown(ListModel *listModel,
00120                        ScrollArea *scrollArea,
00121                        ListBox *listBox)
00122     {
00123         setWidth(100);
00124         setFocusable(true);
00125         mDroppedDown = false;
00126         mPushed = false;
00127     
00128         mDefaultScrollArea = NULL;
00129         mDefaultListBox = NULL;
00130 
00131         mScrollArea = scrollArea;
00132         mScrollArea->_setFocusHandler(&mFocusHandler);
00133 
00134         mListBox = listBox;    
00135         mListBox->addActionListener(this);
00136         mScrollArea->setContent(mListBox);
00137         mScrollArea->_setParent(this);
00138             
00139         setListModel(listModel);
00140 
00141         if (mListBox->getSelected() < 0)
00142         {
00143             mListBox->setSelected(0);
00144         }
00145 
00146         addMouseListener(this);
00147         addKeyListener(this);
00148         adjustHeight();
00149         setBorderSize(1);        
00150     }
00151 
00152     DropDown::~DropDown()
00153     {      
00154         if (mScrollArea != NULL)
00155         {
00156             mScrollArea->_setFocusHandler(NULL);
00157         }
00158 
00159         if (mDefaultScrollArea != NULL)
00160         {
00161             delete mDefaultScrollArea;
00162         }
00163 
00164         if (mDefaultListBox != NULL)
00165         {
00166             delete mDefaultListBox;
00167         }
00168 
00169         if (widgetExists(mListBox))
00170         {
00171             mListBox->removeActionListener(this);
00172         }
00173     }
00174   
00175     void DropDown::logic()
00176     {
00177         if (mScrollArea == NULL || mScrollArea->getContent() == NULL)
00178         {
00179             throw GCN_EXCEPTION("ScrollArea or ListBox is NULL.");
00180         }
00181       
00182         mScrollArea->logic();
00183         mFocusHandler.applyChanges();
00184     }
00185     
00186     void DropDown::draw(Graphics* graphics)
00187     {     
00188         if (mScrollArea == NULL || mScrollArea->getContent() == NULL)
00189         {
00190             throw GCN_EXCEPTION("ScrollArea or ListBox is NULL.");
00191         }
00192 
00193         int h;
00194 
00195         if (mDroppedDown)
00196         {
00197             h = mOldH;
00198         }
00199         else
00200         {
00201             h = getHeight();
00202         }
00203     
00204         int alpha = getBaseColor().a;
00205         Color faceColor = getBaseColor();
00206         faceColor.a = alpha;
00207         Color highlightColor = faceColor + 0x303030;
00208         highlightColor.a = alpha;
00209         Color shadowColor = faceColor - 0x303030;      
00210         shadowColor.a = alpha;    
00211         
00212 
00213         graphics->setColor(getBackgroundColor());
00214         graphics->fillRectangle(Rectangle(0, 0, getWidth(), h));
00215    
00216         graphics->setColor(getForegroundColor());
00217         graphics->setFont(getFont());
00218     
00219         if (mListBox->getListModel() && mListBox->getSelected() >= 0)
00220         {
00221             graphics->drawText(mListBox->getListModel()->getElementAt(mListBox->getSelected()), 1, 0);
00222         }
00223 
00224         if (hasFocus())
00225         {
00226             graphics->drawRectangle(Rectangle(0, 0, getWidth() - h, h));
00227         }
00228         
00229         drawButton(graphics);
00230             
00231          if (mDroppedDown)
00232          {
00233              graphics->pushClipArea(mScrollArea->getDimension());
00234              mScrollArea->draw(graphics);
00235              graphics->popClipArea();
00236 
00237             // Draw two lines separating the ListBox with se selected
00238             // element view.
00239             graphics->setColor(highlightColor);
00240             graphics->drawLine(0, h, getWidth(), h);
00241             graphics->setColor(shadowColor);
00242             graphics->drawLine(0, h + 1,getWidth(),h + 1);
00243          }        
00244     }
00245 
00246     void DropDown::drawBorder(Graphics* graphics)
00247     {
00248         Color faceColor = getBaseColor();
00249         Color highlightColor, shadowColor;
00250         int alpha = getBaseColor().a;
00251         int width = getWidth() + getBorderSize() * 2 - 1;
00252         int height = getHeight() + getBorderSize() * 2 - 1;
00253         highlightColor = faceColor + 0x303030;
00254         highlightColor.a = alpha;
00255         shadowColor = faceColor - 0x303030;
00256         shadowColor.a = alpha;
00257         
00258         unsigned int i;
00259         for (i = 0; i < getBorderSize(); ++i)
00260         {
00261             graphics->setColor(shadowColor);
00262             graphics->drawLine(i,i, width - i, i);
00263             graphics->drawLine(i,i + 1, i, height - i - 1);
00264             graphics->setColor(highlightColor);
00265             graphics->drawLine(width - i,i + 1, width - i, height - i); 
00266             graphics->drawLine(i,height - i, width - i - 1, height - i); 
00267         }
00268     }
00269 
00270     void DropDown::drawButton(Graphics *graphics)
00271     {
00272         Color faceColor, highlightColor, shadowColor;
00273         int offset;
00274         int alpha = getBaseColor().a;
00275         
00276         if (mPushed)
00277         {
00278             faceColor = getBaseColor() - 0x303030;
00279             faceColor.a = alpha;
00280             highlightColor = faceColor - 0x303030;
00281             highlightColor.a = alpha;
00282             shadowColor = faceColor + 0x303030;
00283             shadowColor.a = alpha;
00284             offset = 1;
00285         }
00286         else
00287         {
00288             faceColor = getBaseColor();
00289             faceColor.a = alpha;
00290             highlightColor = faceColor + 0x303030;
00291             highlightColor.a = alpha;
00292             shadowColor = faceColor - 0x303030;
00293             shadowColor.a = alpha;
00294             offset = 0;
00295         }
00296 
00297         int h;
00298         if (mDroppedDown)
00299         {
00300             h = mOldH;
00301         }
00302         else
00303         {
00304             h = getHeight();
00305         }
00306         int x = getWidth() - h;
00307         int y = 0;    
00308 
00309         graphics->setColor(faceColor);
00310         graphics->fillRectangle(Rectangle(x+1, y+1, h-2, h-2));
00311 
00312         graphics->setColor(highlightColor);
00313         graphics->drawLine(x, y, x+h-1, y);
00314         graphics->drawLine(x, y+1, x, y+h-1);
00315 
00316         graphics->setColor(shadowColor);
00317         graphics->drawLine(x+h-1, y+1, x+h-1, y+h-1);
00318         graphics->drawLine(x+1, y+h-1, x+h-2, y+h-1);
00319 
00320         graphics->setColor(getForegroundColor());
00321     
00322         int i;
00323         int hh = h / 3;
00324         int hx = x + h / 2;
00325         int hy = y + (h * 2) / 3;
00326         for (i=0; i<hh; i++)
00327         {
00328             graphics->drawLine(hx - i + offset,
00329                                hy - i + offset,
00330                                hx + i + offset,
00331                                hy - i + offset);
00332         }        
00333     }
00334     
00335     int DropDown::getSelected()
00336     {
00337         if (mScrollArea == NULL || mScrollArea->getContent() == NULL)
00338         {
00339             throw GCN_EXCEPTION("ScrollArea or ListBox is NULL.");
00340         }
00341 
00342         return mListBox->getSelected();        
00343     }
00344     
00345     void DropDown::setSelected(int selected)
00346     {
00347         if (mScrollArea == NULL || mScrollArea->getContent() == NULL)
00348         {
00349             throw GCN_EXCEPTION("ScrollArea or ListBox is NULL.");
00350         }
00351 
00352         if (selected >= 0)
00353         {
00354             mListBox->setSelected(selected);
00355         }        
00356     }
00357     
00358     void DropDown::keyPress(const Key& key)
00359     {
00360         if (mScrollArea == NULL || mScrollArea->getContent() == NULL)
00361         {
00362             throw GCN_EXCEPTION("ScrollArea or ListBox is NULL.");
00363         }
00364 
00365         if ((key.getValue() == Key::ENTER || key.getValue() == Key::SPACE)
00366             && !mDroppedDown)
00367         {
00368             dropDown();
00369         }        
00370     }
00371   
00372     void DropDown::mousePress(int x, int y, int button)
00373     {
00374         if (button == MouseInput::LEFT && hasMouse() && !mDroppedDown)
00375         {
00376             mPushed = true;
00377             dropDown();
00378         }
00379         // Fold up the listbox if the upper part is clicked after fold down
00380         else if (button == MouseInput::LEFT && hasMouse() && mDroppedDown
00381                  && y < mOldH)
00382         {
00383             foldUp();
00384         }
00385         else if (!hasMouse())
00386         {
00387             foldUp();
00388         }        
00389     }
00390 
00391     void DropDown::mouseRelease(int x, int y, int button)
00392     {
00393         if (button == MouseInput::LEFT)
00394         {      
00395             mPushed = false;
00396         }
00397     }
00398   
00399     void DropDown::setListModel(ListModel *listModel)
00400     {
00401         if (mScrollArea == NULL || mScrollArea->getContent() == NULL)
00402         {
00403             throw GCN_EXCEPTION("ScrollArea or ListBox is NULL.");
00404         }
00405 
00406         mListBox->setListModel(listModel);
00407     
00408         if (mListBox->getSelected() < 0)
00409         {
00410             mListBox->setSelected(0);
00411         }
00412     
00413         adjustHeight();        
00414     }
00415   
00416     ListModel *DropDown::getListModel()
00417     {
00418         if (mScrollArea == NULL || mScrollArea->getContent() == NULL)
00419         {
00420             throw GCN_EXCEPTION("ScrollArea or ListBox is NULL.");
00421         }
00422       
00423         return mListBox->getListModel();        
00424     }
00425 
00426     void DropDown::setScrollArea(ScrollArea *scrollArea)
00427     {
00428         mScrollArea->_setFocusHandler(NULL);
00429         mScrollArea->_setParent(NULL);
00430         mScrollArea = scrollArea;
00431         mScrollArea->_setFocusHandler(&mFocusHandler);
00432         mScrollArea->setContent(mListBox);
00433         mScrollArea->_setParent(this);
00434         adjustHeight();        
00435     }
00436 
00437     ScrollArea *DropDown::getScrollArea()
00438     {
00439         return mScrollArea;        
00440     }
00441   
00442     void DropDown::setListBox(ListBox *listBox)
00443     {
00444         listBox->setSelected(mListBox->getSelected());
00445         listBox->setListModel(mListBox->getListModel());
00446         listBox->addActionListener(this);
00447 
00448         if (mScrollArea->getContent() != NULL)
00449         {
00450             mListBox->removeActionListener(this);
00451         }
00452         
00453         mListBox = listBox;
00454     
00455         mScrollArea->setContent(mListBox);
00456     
00457         if (mListBox->getSelected() < 0)
00458         {
00459             mListBox->setSelected(0);
00460         }       
00461     }
00462 
00463     ListBox *DropDown::getListBox()
00464     {
00465         return mListBox;        
00466     }
00467   
00468     void DropDown::adjustHeight()
00469     {
00470         if (mScrollArea == NULL || mScrollArea->getContent() == NULL)
00471         {
00472             throw GCN_EXCEPTION("ScrollArea or ListBox is NULL.");
00473         }
00474 
00475         int listBoxHeight = mListBox->getHeight();
00476         int h2 = getFont()->getHeight();
00477 
00478         setHeight(h2);
00479 
00480         // The addition/subtraction of 2 compensates for the seperation lines
00481         // seperating the selected element view and the scroll area.
00482         
00483         if (mDroppedDown && getParent())
00484         {
00485             int h = getParent()->getHeight() - getY();
00486       
00487             if (listBoxHeight > h - h2 - 2)
00488             {
00489                 mScrollArea->setHeight(h - h2 - 2);
00490                 setHeight(h);
00491             }
00492             else
00493             {
00494                 setHeight(listBoxHeight + h2 + 2);
00495                 mScrollArea->setHeight(listBoxHeight);
00496             }
00497         }
00498 
00499         mScrollArea->setWidth(getWidth());
00500         mScrollArea->setPosition(0, h2 + 2);        
00501     }
00502 
00503     void DropDown::dropDown()
00504     {        
00505         if (!mDroppedDown)
00506         {
00507             mDroppedDown = true;
00508             mOldH = getHeight();
00509             adjustHeight();
00510 
00511             if (getParent())
00512             {
00513                 getParent()->moveToTop(this);
00514             }
00515         }
00516         
00517         mFocusHandler.requestFocus(mScrollArea->getContent());
00518     }
00519     
00520     void DropDown::foldUp()
00521     {        
00522         if (mDroppedDown)
00523         {
00524             mDroppedDown = false;
00525             mFocusHandler.focusNone();
00526             adjustHeight();
00527         }        
00528     }
00529 
00530     void DropDown::_keyInputMessage(const KeyInput& keyInput)
00531     {        
00532         if (mDroppedDown)
00533         {
00534             if (mScrollArea == NULL || mScrollArea->getContent() == NULL)
00535             {
00536                 throw GCN_EXCEPTION("ScrollArea or ListBox is NULL.");
00537             }
00538 
00539             if (mFocusHandler.getFocused() != NULL)
00540             {
00541                 mFocusHandler.getFocused()->_keyInputMessage(keyInput);
00542             }
00543         }
00544         else
00545         {
00546             BasicContainer::_keyInputMessage(keyInput);
00547         }        
00548     }
00549     
00550     void DropDown::_mouseInputMessage(const MouseInput &mouseInput)
00551     {            
00552         BasicContainer::_mouseInputMessage(mouseInput);
00553 
00554         if (mDroppedDown)
00555         {
00556             if (mScrollArea == NULL || mScrollArea->getContent() == NULL)
00557             {
00558                 throw GCN_EXCEPTION("ScrollArea or ListBox is NULL.");
00559             }
00560                     
00561             if (mouseInput.y >= mOldH)
00562             {
00563                 MouseInput mi = mouseInput;
00564                 mi.y -= mScrollArea->getY();        
00565                 mScrollArea->_mouseInputMessage(mi);
00566 
00567                 if (mListBox->hasFocus())
00568                 {
00569                     mi.y -= mListBox->getY();
00570                     mListBox->_mouseInputMessage(mi);
00571                 }
00572             }
00573         }        
00574     }
00575 
00576     void DropDown::lostFocus()
00577     {
00578         foldUp();        
00579     }
00580 
00581     void DropDown::moveToTop(Widget* widget)
00582     {
00583         if (getParent())
00584         {
00585             getParent()->moveToTop(this);
00586         }        
00587     }
00588 
00589     void DropDown::moveToBottom(Widget* widget)
00590     {
00591         if (getParent())
00592         {
00593             getParent()->moveToBottom(this);
00594         }        
00595     }
00596 
00597     void DropDown::_announceDeath(Widget* widget)
00598     {        
00599         if (widget == mScrollArea)
00600         {            
00601             mScrollArea = NULL;
00602         }
00603         else
00604         {
00605             throw GCN_EXCEPTION("Death announced for unknown widget..");
00606         }        
00607     }
00608 
00609     void DropDown::action(const std::string& eventId)
00610     {
00611         foldUp();
00612         generateAction();        
00613     } 
00614 
00615     void DropDown::getDrawSize(int& width, int& height, Widget* widget)
00616     {
00617         if (widget == mScrollArea)
00618         {
00619             if (mDroppedDown)
00620             {
00621                 height = getHeight() - mOldH;
00622                 width = getWidth();
00623             }
00624             else
00625             {
00626                 width = height = 0;
00627             }
00628         }
00629         else
00630         {
00631             throw GCN_EXCEPTION("DropDown::getDrawSize. widget is not the ScrollArea (wieeerd...)");
00632         }        
00633     }
00634 
00635     void DropDown::setBaseColor(const Color& color)
00636     {
00637         if (mDefaultScrollArea == mScrollArea && mScrollArea != NULL)
00638         {
00639             mScrollArea->setBaseColor(color);
00640         }
00641 
00642         if (mDefaultListBox == mListBox && mListBox != NULL)
00643         {
00644             mListBox->setBaseColor(color);
00645         }
00646                 
00647         Widget::setBaseColor(color);
00648     }
00649 
00650     void DropDown::setBackgroundColor(const Color& color)
00651     {
00652         if (mDefaultScrollArea == mScrollArea && mScrollArea != NULL)
00653         {
00654             mScrollArea->setBackgroundColor(color);
00655         }
00656 
00657         if (mDefaultListBox == mListBox && mListBox != NULL)
00658         {
00659             mListBox->setBackgroundColor(color);
00660         }
00661                 
00662         Widget::setBackgroundColor(color);
00663     }
00664 
00665     void DropDown::setForegroundColor(const Color& color)
00666     {
00667         if (mDefaultScrollArea == mScrollArea && mScrollArea != NULL)
00668         {
00669             mScrollArea->setForegroundColor(color);
00670         }
00671 
00672         if (mDefaultListBox == mListBox && mListBox != NULL)
00673         {
00674             mListBox->setForegroundColor(color);
00675         }
00676                 
00677         Widget::setForegroundColor(color);
00678     }     
00679 }
00680 

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