basiccontainer.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 /*
00058  * For comments regarding functions please see the header file.
00059  */
00060 
00061 #include "guichan/basiccontainer.hpp"
00062 
00063 #include <algorithm>
00064 
00065 #include "guichan/exception.hpp"
00066 #include "guichan/focushandler.hpp"
00067 #include "guichan/graphics.hpp"
00068 #include "guichan/mouseinput.hpp"
00069 
00070 namespace gcn
00071 {
00072     BasicContainer::BasicContainer()
00073     {
00074         mWidgetWithMouse = NULL;
00075         mMouseInputPolicy = NOT_ON_CHILD;
00076         mInternalFocusHandler = NULL;
00077     }
00078 
00079     BasicContainer::~BasicContainer()
00080     {
00081         clear();
00082     }
00083 
00084     void BasicContainer::moveToTop(Widget* widget)
00085     {
00086         WidgetListIterator iter;
00087         for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
00088         {
00089             if (*iter == widget)
00090             {
00091                 mWidgets.erase(iter);
00092                 mWidgets.push_back(widget);
00093                 return;
00094             }
00095         }
00096 
00097         throw GCN_EXCEPTION("There is no such widget in this container.");
00098     }
00099 
00100     void BasicContainer::moveToBottom(Widget* widget)
00101     {
00102         WidgetListIterator iter;
00103         iter = find(mWidgets.begin(), mWidgets.end(), widget);
00104 
00105         if (iter == mWidgets.end())
00106         {
00107             throw GCN_EXCEPTION("There is no such widget in this container.");
00108         }
00109         mWidgets.erase(iter);
00110         mWidgets.push_front(widget);
00111     }
00112 
00113     void BasicContainer::_announceDeath(Widget *widget)
00114     {
00115         if (mWidgetWithMouse == widget)
00116         {
00117             mWidgetWithMouse = NULL;
00118         }
00119 
00120         WidgetListIterator iter;
00121         iter = find(mWidgets.begin(), mWidgets.end(), widget);
00122 
00123         if (iter == mWidgets.end())
00124         {
00125             throw GCN_EXCEPTION("There is no such widget in this container.");
00126         }
00127 
00128         mWidgets.erase(iter);
00129     }
00130 
00131     Rectangle BasicContainer::getChildrenArea()
00132     {
00133         return Rectangle(0, 0, getWidth(), getHeight());
00134     }
00135 
00136     void BasicContainer::focusNext()
00137     {
00138         WidgetListIterator it;
00139 
00140         for (it = mWidgets.begin(); it != mWidgets.end(); it++)
00141         {
00142             if ((*it)->isFocused())
00143             {
00144                 break;
00145             }
00146         }
00147 
00148         WidgetListIterator end = it;
00149 
00150         if (it == mWidgets.end())
00151         {
00152             it = mWidgets.begin();
00153         }
00154 
00155         it++;
00156 
00157         for ( ; it != end; it++)
00158         {
00159             if (it == mWidgets.end())
00160             {
00161                 it = mWidgets.begin();
00162             }
00163 
00164             if ((*it)->isFocusable())
00165             {
00166                 (*it)->requestFocus();
00167                 return;
00168             }
00169         }
00170     }
00171 
00172     void BasicContainer::focusPrevious()
00173     {
00174         WidgetListReverseIterator it;
00175 
00176         for (it = mWidgets.rbegin(); it != mWidgets.rend(); it++)
00177         {
00178             if ((*it)->isFocused())
00179             {
00180                 break;
00181             }
00182         }
00183 
00184         WidgetListReverseIterator end = it;
00185 
00186         it++;
00187 
00188         if (it == mWidgets.rend())
00189         {
00190             it = mWidgets.rbegin();
00191         }
00192 
00193         for ( ; it != end; it++)
00194         {
00195             if (it == mWidgets.rend())
00196             {
00197                 it = mWidgets.rbegin();
00198             }
00199 
00200             if ((*it)->isFocusable())
00201             {
00202                 (*it)->requestFocus();
00203                 return;
00204             }
00205         }
00206     }
00207 
00208     Widget *BasicContainer::getWidgetAt(int x, int y)
00209     {
00210         Rectangle r = getChildrenArea();
00211 
00212         if (!r.isPointInRect(x, y))
00213         {
00214             return NULL;
00215         }
00216 
00217         x -= r.x;
00218         y -= r.y;
00219 
00220         WidgetListReverseIterator it;
00221         for (it = mWidgets.rbegin(); it != mWidgets.rend(); it++)
00222         {
00223             if ((*it)->isVisible() && (*it)->getDimension().isPointInRect(x, y))
00224             {
00225                 return (*it);
00226             }
00227         }
00228 
00229         return NULL;
00230     }
00231 
00232     void BasicContainer::logic()
00233     {
00234         logicChildren();
00235     }
00236 
00237     void BasicContainer::_setFocusHandler(FocusHandler* focusHandler)
00238     {
00239         Widget::_setFocusHandler(focusHandler);
00240 
00241         if (mInternalFocusHandler != NULL)
00242         {
00243             return;
00244         }
00245 
00246 
00247         WidgetListIterator iter;
00248         for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
00249         {
00250             (*iter)->_setFocusHandler(focusHandler);
00251         }
00252     }
00253 
00254     void BasicContainer::_mouseInputMessage(const MouseInput& mouseInput)
00255     {
00256         Widget *newWidgetWithMouse;
00257 
00258         newWidgetWithMouse = getWidgetAt(mouseInput.x, mouseInput.y);
00259 
00260         if (newWidgetWithMouse != mWidgetWithMouse)
00261         {
00262             if (mWidgetWithMouse != NULL)
00263             {
00264                 mWidgetWithMouse->_mouseOutMessage();
00265             }
00266 
00267             if (newWidgetWithMouse != NULL)
00268             {
00269                 newWidgetWithMouse->_mouseInMessage();
00270             }
00271 
00272             mWidgetWithMouse = newWidgetWithMouse;
00273         }
00274 
00275         if (mWidgetWithMouse != NULL)
00276         {
00277             MouseInput mi = mouseInput;
00278             Rectangle ca = getChildrenArea();
00279             mi.x -= mWidgetWithMouse->getX() + ca.x;
00280             mi.y -= mWidgetWithMouse->getY() + ca.y;
00281 
00282             // Clamp the input to widget edges
00283             if (mi.x < 0)
00284             {
00285                 mi.x = 0;
00286             }
00287 
00288             if (mi.y < 0)
00289             {
00290                 mi.y = 0;
00291             }
00292 
00293             if (mi.x >= mWidgetWithMouse->getWidth())
00294             {
00295                 mi.x = mWidgetWithMouse->getWidth() - 1;
00296             }
00297 
00298             if (mi.y >= mWidgetWithMouse->getHeight())
00299             {
00300                 mi.y = mWidgetWithMouse->getHeight() - 1;
00301             }
00302 
00303             mWidgetWithMouse->_mouseInputMessage(mi);
00304         }
00305 
00306         if (mInternalFocusHandler != NULL)
00307         {
00308             Widget *f = mInternalFocusHandler->getFocused();
00309             Widget *d = mInternalFocusHandler->getDragged();
00310 
00311             if (f != NULL && !f->hasMouse() && isFocused())
00312             {
00313                 MouseInput mi = mouseInput;
00314                 Rectangle ca = getChildrenArea();
00315                 mi.x -= f->getX() + ca.x;
00316                 mi.y -= f->getY() + ca.y;
00317 
00318                 f->_mouseInputMessage(mi);
00319             }
00320 
00321             if (d != NULL && f != d && !d->hasMouse() && isDragged())
00322             {
00323                 MouseInput mi = mouseInput;
00324                 Rectangle ca = getChildrenArea();
00325                 mi.x -= d->getX() + ca.x;
00326                 mi.y -= d->getY() + ca.y;
00327 
00328                 d->_mouseInputMessage(mi);
00329             }
00330         }
00331 
00332         bool toContainer = isDragged();
00333 
00334         switch (mMouseInputPolicy)
00335         {
00336           case NEVER:
00337               break;
00338           case ALWAYS:
00339               toContainer = true;
00340               break;
00341           case NOT_ON_CHILD:
00342               if (mWidgetWithMouse == NULL)
00343               {
00344                   toContainer = true;
00345               }
00346               break;
00347           case NOT_IN_CHILDREN_AREA:
00348               if (!getChildrenArea().isPointInRect(mouseInput.x, mouseInput.y))
00349               {
00350                   toContainer = true;
00351               }
00352           default:
00353               throw GCN_EXCEPTION("Unknown mouse input policy");
00354         }
00355 
00356         if (toContainer)
00357         {
00358             Widget::_mouseInputMessage(mouseInput);
00359         }
00360     }
00361 
00362     void BasicContainer::_mouseOutMessage()
00363     {
00364         if (mWidgetWithMouse != NULL)
00365         {
00366             mWidgetWithMouse->_mouseOutMessage();
00367             mWidgetWithMouse = NULL;
00368         }
00369 
00370         Widget::_mouseOutMessage();
00371     }
00372 
00373     void BasicContainer::add(Widget* widget)
00374     {
00375         mWidgets.push_back(widget);
00377 
00378         if (mInternalFocusHandler == NULL)
00379         {
00380             widget->_setFocusHandler(_getFocusHandler());
00381         }
00382         else
00383         {
00384             widget->_setFocusHandler(mInternalFocusHandler);
00385         }
00386 
00387         widget->_setParent(this);
00388     }
00389 
00390     void BasicContainer::remove(Widget* widget)
00391     {
00392         if (widget == mWidgetWithMouse)
00393         {
00394             mWidgetWithMouse = NULL;
00395         }
00396 
00397         WidgetListIterator iter;
00398         for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
00399         {
00400             if (*iter == widget)
00401             {
00402                 mWidgets.erase(iter);
00403                 widget->_setFocusHandler(NULL);
00404                 widget->_setParent(NULL);
00405                 return;
00406             }
00407         }
00408 
00409         throw GCN_EXCEPTION("There is no such widget in this container.");
00410     }
00411 
00412     void BasicContainer::clear()
00413     {
00414         mWidgetWithMouse = NULL;
00415 
00416         WidgetListIterator iter;
00417 
00418         for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
00419         {
00420             (*iter)->_setFocusHandler(NULL);
00421             (*iter)->_setParent(NULL);
00422         }
00423 
00424         mWidgets.clear();
00425     }
00426 
00427     void BasicContainer::drawChildren(Graphics* graphics)
00428     {
00429         graphics->pushClipArea(getChildrenArea());
00430 
00431         WidgetListIterator iter;
00432         for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
00433         {
00434             if ((*iter)->isVisible())
00435             {
00436                 // If the widget has a border,
00437                 // draw it before drawing the widget
00438                 if ((*iter)->getBorderSize() > 0)
00439                 {
00440                     Rectangle rec = (*iter)->getDimension();
00441                     rec.x -= (*iter)->getBorderSize();
00442                     rec.y -= (*iter)->getBorderSize();
00443                     rec.width += 2 * (*iter)->getBorderSize();
00444                     rec.height += 2 * (*iter)->getBorderSize();
00445                     graphics->pushClipArea(rec);
00446                     (*iter)->drawBorder(graphics);
00447                     graphics->popClipArea();
00448                 }
00449 
00450                 graphics->pushClipArea((*iter)->getDimension());
00451                 (*iter)->draw(graphics);
00452                 graphics->popClipArea();
00453             }
00454         }
00455 
00456         graphics->popClipArea();
00457     }
00458 
00459     void BasicContainer::logicChildren()
00460     {
00461         WidgetListIterator iter;
00462         for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
00463         {
00464             (*iter)->logic();
00465         }
00466     }
00467 
00468     void BasicContainer::setMouseInputPolicy(unsigned int policy)
00469     {
00470         mMouseInputPolicy = policy;
00471     }
00472 
00473     unsigned int BasicContainer::getMouseInputPolicy()
00474     {
00475         return mMouseInputPolicy;
00476     }
00477 
00478     void BasicContainer::showWidgetPart(Widget* widget, Rectangle area)
00479     {
00480         Rectangle widgetArea = getChildrenArea();
00481         area.x += widget->getX();
00482         area.y += widget->getY();
00483 
00484         if (area.x + area.width > widgetArea.width)
00485         {
00486             widget->setX(widget->getX() - area.x - area.width + widgetArea.width);
00487         }
00488 
00489         if (area.y + area.height > widgetArea.height)
00490         {
00491             widget->setY(widget->getY() - area.y - area.height + widgetArea.height);
00492         }
00493 
00494         if (area.x < 0)
00495         {
00496             widget->setX(widget->getX() - area.x);
00497         }
00498 
00499         if (area.y < 0)
00500         {
00501             widget->setY(widget->getY() - area.y);
00502         }
00503     }
00504 
00505     FocusHandler* BasicContainer::getInternalFocusHandler()
00506     {
00507         return mFocusHandler;
00508     }
00509 
00510     void BasicContainer::setInternalFocusHandler(FocusHandler* focusHandler)
00511     {
00512         mInternalFocusHandler = focusHandler;
00513 
00514         WidgetListIterator iter;
00515         for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
00516         {
00517             if (mInternalFocusHandler == NULL)
00518             {
00519                 (*iter)->_setFocusHandler(_getFocusHandler());
00520             }
00521             else
00522             {
00523                 (*iter)->_setFocusHandler(mInternalFocusHandler);
00524             }
00525         }
00526     }
00527 
00528     void BasicContainer::_keyInputMessage(const KeyInput& keyInput)
00529     {
00530         if (mInternalFocusHandler != NULL && mInternalFocusHandler->getFocused() != NULL)
00531         {
00532             mInternalFocusHandler->getFocused()->_keyInputMessage(keyInput);
00533         }
00534         else
00535         {
00536             Widget::_keyInputMessage(keyInput);
00537         }
00538     }
00539 }

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