dropdown.cpp

00001 /*      _______   __   __   __   ______   __   __   _______   __   __
00002  *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
00003  *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
00004  *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
00005  *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
00006  * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
00007  * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
00008  *
00009  * Copyright (c) 2004, 2005, 2006 Olof Naessén and Per Larsson
00010  *
00011  *                                                         Js_./
00012  * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
00013  * Olof Naessén a.k.a jansem/yakslem                _asww7!uY`>  )\a//
00014  *                                                 _Qhm`] _f "'c  1!5m
00015  * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
00016  *                                               .)j(] .d_/ '-(  P .   S
00017  * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
00018  * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
00019  * binary forms, with or without                 )4d[#7r, .   '     )d`)[
00020  * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
00021  * that the following conditions are met:       j<<WP+k/);.        _W=j f
00022  * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
00023  *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
00024  *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
00025  *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
00026  * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
00027  *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
00028  *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
00029  *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
00030  *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
00031  *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
00032  * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
00033  *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
00034  *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
00035  *    from this software without specific        (js, \[QQW$QWW#?!V"".
00036  *    prior written permission.                    ]y:.<\..          .
00037  *                                                 -]n w/ '         [.
00038  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
00039  * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
00040  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
00041  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
00042  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
00043  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
00044  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
00045  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
00046  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
00047  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
00048  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
00049  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
00050  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00051  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00052  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00053  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00054  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00055  */
00056 
00057 #include "guichan/widgets/dropdown.hpp"
00058 
00059 #include "guichan/exception.hpp"
00060 #include "guichan/font.hpp"
00061 #include "guichan/graphics.hpp"
00062 #include "guichan/key.hpp"
00063 #include "guichan/listmodel.hpp"
00064 #include "guichan/mouseinput.hpp"
00065 #include "guichan/widgets/listbox.hpp"
00066 #include "guichan/widgets/scrollarea.hpp"
00067 
00068 namespace gcn
00069 {
00070 
00071     DropDown::DropDown(ListModel *listModel,
00072                        ScrollArea *scrollArea,
00073                        ListBox *listBox)
00074     {
00075         setWidth(100);
00076         setFocusable(true);
00077         mDroppedDown = false;
00078         mPushed = false;
00079 
00080         setInternalFocusHandler(&mFocusHandler);
00081 
00082         mInternalScrollArea = (scrollArea == NULL);
00083         mInternalListBox = (listBox == NULL);
00084 
00085         if (mInternalScrollArea)
00086         {
00087             mScrollArea = new ScrollArea();
00088             mScrollArea->setVerticalScrollPolicy(ScrollArea::SHOW_ALWAYS);
00089         }
00090         else
00091         {
00092             mScrollArea = scrollArea;
00093         }
00094 
00095         if (mInternalListBox)
00096         {
00097             mListBox = new ListBox();
00098         }
00099         else
00100         {
00101             mListBox = listBox;
00102         }
00103 
00104         mScrollArea->setContent(mListBox);
00105         add(mScrollArea);
00106 
00107         mListBox->addActionListener(this);
00108 
00109         setListModel(listModel);
00110 
00111         if (mListBox->getSelected() < 0)
00112         {
00113             mListBox->setSelected(0);
00114         }
00115 
00116         addMouseListener(this);
00117         addKeyListener(this);
00118         adjustHeight();
00119         setBorderSize(1);
00120     }
00121 
00122     DropDown::~DropDown()
00123     {
00124         if (mInternalScrollArea)
00125         {
00126             delete mScrollArea;
00127         }
00128 
00129         if (mInternalListBox)
00130         {
00131             delete mListBox;
00132         }
00133 
00134         if (widgetExists(mListBox))
00135         {
00136             mListBox->removeActionListener(this);
00137         }
00138     }
00139 
00140     void DropDown::draw(Graphics* graphics)
00141     {
00142         int h;
00143 
00144         if (mDroppedDown)
00145         {
00146             h = mOldH;
00147         }
00148         else
00149         {
00150             h = getHeight();
00151         }
00152 
00153         int alpha = getBaseColor().a;
00154         Color faceColor = getBaseColor();
00155         faceColor.a = alpha;
00156         Color highlightColor = faceColor + 0x303030;
00157         highlightColor.a = alpha;
00158         Color shadowColor = faceColor - 0x303030;
00159         shadowColor.a = alpha;
00160 
00161 
00162         graphics->setColor(getBackgroundColor());
00163         graphics->fillRectangle(Rectangle(0, 0, getWidth(), h));
00164 
00165         graphics->setColor(getForegroundColor());
00166         graphics->setFont(getFont());
00167 
00168         if (mListBox->getListModel() && mListBox->getSelected() >= 0)
00169         {
00170             graphics->drawText(mListBox->getListModel()->getElementAt(mListBox->getSelected()), 1, 0);
00171         }
00172 
00173         if (isFocused())
00174         {
00175             graphics->drawRectangle(Rectangle(0, 0, getWidth() - h, h));
00176         }
00177 
00178         drawButton(graphics);
00179 
00180          if (mDroppedDown)
00181          {
00182              drawChildren(graphics);
00183 
00184             // Draw two lines separating the ListBox with se selected
00185             // element view.
00186             graphics->setColor(highlightColor);
00187             graphics->drawLine(0, h, getWidth(), h);
00188             graphics->setColor(shadowColor);
00189             graphics->drawLine(0, h + 1,getWidth(),h + 1);
00190          }
00191     }
00192 
00193     void DropDown::drawBorder(Graphics* graphics)
00194     {
00195         Color faceColor = getBaseColor();
00196         Color highlightColor, shadowColor;
00197         int alpha = getBaseColor().a;
00198         int width = getWidth() + getBorderSize() * 2 - 1;
00199         int height = getHeight() + getBorderSize() * 2 - 1;
00200         highlightColor = faceColor + 0x303030;
00201         highlightColor.a = alpha;
00202         shadowColor = faceColor - 0x303030;
00203         shadowColor.a = alpha;
00204 
00205         unsigned int i;
00206         for (i = 0; i < getBorderSize(); ++i)
00207         {
00208             graphics->setColor(shadowColor);
00209             graphics->drawLine(i,i, width - i, i);
00210             graphics->drawLine(i,i + 1, i, height - i - 1);
00211             graphics->setColor(highlightColor);
00212             graphics->drawLine(width - i,i + 1, width - i, height - i);
00213             graphics->drawLine(i,height - i, width - i - 1, height - i);
00214         }
00215     }
00216 
00217     void DropDown::drawButton(Graphics *graphics)
00218     {
00219         Color faceColor, highlightColor, shadowColor;
00220         int offset;
00221         int alpha = getBaseColor().a;
00222 
00223         if (mPushed)
00224         {
00225             faceColor = getBaseColor() - 0x303030;
00226             faceColor.a = alpha;
00227             highlightColor = faceColor - 0x303030;
00228             highlightColor.a = alpha;
00229             shadowColor = faceColor + 0x303030;
00230             shadowColor.a = alpha;
00231             offset = 1;
00232         }
00233         else
00234         {
00235             faceColor = getBaseColor();
00236             faceColor.a = alpha;
00237             highlightColor = faceColor + 0x303030;
00238             highlightColor.a = alpha;
00239             shadowColor = faceColor - 0x303030;
00240             shadowColor.a = alpha;
00241             offset = 0;
00242         }
00243 
00244         int h;
00245         if (mDroppedDown)
00246         {
00247             h = mOldH;
00248         }
00249         else
00250         {
00251             h = getHeight();
00252         }
00253         int x = getWidth() - h;
00254         int y = 0;
00255 
00256         graphics->setColor(faceColor);
00257         graphics->fillRectangle(Rectangle(x+1, y+1, h-2, h-2));
00258 
00259         graphics->setColor(highlightColor);
00260         graphics->drawLine(x, y, x+h-1, y);
00261         graphics->drawLine(x, y+1, x, y+h-1);
00262 
00263         graphics->setColor(shadowColor);
00264         graphics->drawLine(x+h-1, y+1, x+h-1, y+h-1);
00265         graphics->drawLine(x+1, y+h-1, x+h-2, y+h-1);
00266 
00267         graphics->setColor(getForegroundColor());
00268 
00269         int i;
00270         int hh = h / 3;
00271         int hx = x + h / 2;
00272         int hy = y + (h * 2) / 3;
00273         for (i=0; i<hh; i++)
00274         {
00275             graphics->drawLine(hx - i + offset,
00276                                hy - i + offset,
00277                                hx + i + offset,
00278                                hy - i + offset);
00279         }
00280     }
00281 
00282     int DropDown::getSelected()
00283     {
00284         return mListBox->getSelected();
00285     }
00286 
00287     void DropDown::setSelected(int selected)
00288     {
00289         if (selected >= 0)
00290         {
00291             mListBox->setSelected(selected);
00292         }
00293     }
00294 
00295     void DropDown::keyPress(const Key& key)
00296     {
00297         if ((key.getValue() == Key::ENTER || key.getValue() == Key::SPACE)
00298             && !mDroppedDown)
00299         {
00300             dropDown();
00301         }
00302     }
00303 
00304     void DropDown::mousePress(int x, int y, int button)
00305     {
00306         if (button == MouseInput::LEFT && hasMouse() && !mDroppedDown)
00307         {
00308             mPushed = true;
00309             dropDown();
00310         }
00311         // Fold up the listbox if the upper part is clicked after fold down
00312         else if (button == MouseInput::LEFT && hasMouse() && mDroppedDown
00313                  && y < mOldH)
00314         {
00315             foldUp();
00316         }
00317         else if (!hasMouse())
00318         {
00319             foldUp();
00320         }
00321     }
00322 
00323     void DropDown::mouseRelease(int x, int y, int button)
00324     {
00325         if (button == MouseInput::LEFT)
00326         {
00327             mPushed = false;
00328         }
00329     }
00330 
00331     void DropDown::setListModel(ListModel *listModel)
00332     {
00333         mListBox->setListModel(listModel);
00334 
00335         if (mListBox->getSelected() < 0)
00336         {
00337             mListBox->setSelected(0);
00338         }
00339 
00340         adjustHeight();
00341     }
00342 
00343     ListModel *DropDown::getListModel()
00344     {
00345         return mListBox->getListModel();
00346     }
00347 
00348     void DropDown::adjustHeight()
00349     {
00350         if (mScrollArea == NULL)
00351         {
00352             throw GCN_EXCEPTION("ScrollArea has been deleted.");
00353         }
00354 
00355         int listBoxHeight = mListBox->getHeight();
00356         int h2 = getFont()->getHeight();
00357 
00358         setHeight(h2);
00359 
00360         // The addition/subtraction of 2 compensates for the seperation lines
00361         // seperating the selected element view and the scroll area.
00362 
00363         if (mDroppedDown && getParent())
00364         {
00365             int h = getParent()->getChildrenArea().height - getY();
00366 
00367             if (listBoxHeight > h - h2 - 2)
00368             {
00369                 mScrollArea->setHeight(h - h2 - 2);
00370                 setHeight(h);
00371             }
00372             else
00373             {
00374                 setHeight(listBoxHeight + h2 + 2);
00375                 mScrollArea->setHeight(listBoxHeight);
00376             }
00377         }
00378 
00379         mScrollArea->setWidth(getWidth());
00380         // Resize the ListBox to exactly fit the ScrollArea.
00381         mListBox->setWidth(mScrollArea->getChildrenArea().width);
00382         mScrollArea->setPosition(0, 0);
00383     }
00384 
00385     void DropDown::dropDown()
00386     {
00387         if (!mDroppedDown)
00388         {
00389             mDroppedDown = true;
00390             mOldH = getHeight();
00391             adjustHeight();
00392 
00393             if (getParent())
00394             {
00395                 getParent()->moveToTop(this);
00396             }
00397         }
00398 
00399         mListBox->requestFocus();
00400     }
00401 
00402     void DropDown::foldUp()
00403     {
00404         if (mDroppedDown)
00405         {
00406             mDroppedDown = false;
00407             mFocusHandler.focusNone();
00408             adjustHeight();
00409         }
00410     }
00411 
00412     void DropDown::lostFocus()
00413     {
00414         foldUp();
00415     }
00416 
00417 
00418     void DropDown::_announceDeath(Widget* widget)
00419     {
00420         if (widget == mScrollArea)
00421         {
00422             mScrollArea = NULL;
00423             BasicContainer::_announceDeath(widget);
00424         }
00425         else
00426         {
00427             throw GCN_EXCEPTION("Death announced for unknown widget..");
00428         }
00429     }
00430 
00431     void DropDown::action(const std::string& eventId, Widget* widget)
00432     {
00433         foldUp();
00434         generateAction();
00435     }
00436 
00437     Rectangle DropDown::getChildrenArea()
00438     {
00439         if (mDroppedDown)
00440         {
00441             return Rectangle(0, mOldH + 2, getWidth(), getHeight() - mOldH);
00442         }
00443 
00444         return Rectangle();
00445     }
00446 
00447     void DropDown::setBaseColor(const Color& color)
00448     {
00449         if (mInternalScrollArea)
00450         {
00451             mScrollArea->setBaseColor(color);
00452         }
00453 
00454         if (mInternalListBox)
00455         {
00456             mListBox->setBaseColor(color);
00457         }
00458 
00459         Widget::setBaseColor(color);
00460     }
00461 
00462     void DropDown::setBackgroundColor(const Color& color)
00463     {
00464         if (mInternalScrollArea)
00465         {
00466             mScrollArea->setBackgroundColor(color);
00467         }
00468 
00469         if (mInternalListBox)
00470         {
00471             mListBox->setBackgroundColor(color);
00472         }
00473 
00474         Widget::setBackgroundColor(color);
00475     }
00476 
00477     void DropDown::setForegroundColor(const Color& color)
00478     {
00479         if (mInternalScrollArea)
00480         {
00481             mScrollArea->setForegroundColor(color);
00482         }
00483 
00484         if (mInternalListBox)
00485         {
00486             mListBox->setForegroundColor(color);
00487         }
00488 
00489         Widget::setForegroundColor(color);
00490     }
00491 
00492     void DropDown::logic()
00493     {
00494         mFocusHandler.applyChanges();
00495         BasicContainer::logic();
00496     }
00497 
00498     void DropDown::setFont(Font *font)
00499     {
00500         if (mInternalScrollArea)
00501         {
00502             mScrollArea->setFont(font);
00503         }
00504 
00505         if (mInternalListBox)
00506         {
00507             mListBox->setFont(font);
00508         }
00509 
00510         Widget::setFont(font);
00511     }
00512 }
00513 

Generated on Sat Jul 29 19:38:48 2006 for Guichan by  doxygen 1.4.7