AaronCameron.net
Not Left, nor right. Just correct.
Not a Member? - Login or Create an Account
Wednesday the 23rd of May 2012 @ 09:30am
Front Page Journal Projects Your Profile About
[]

LibN2L-4 Library Code Reference

Classes
Compounds
Files
Members
Method Index
Full Reference

cGuiCanvas.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002 Nova-2 Library (libN2L, or simply n2l) Game development C++ Library
00003 Copyright (C) 2003  Aaron Cameron
00004 
00005 This library is free software; you can redistribute it and/or
00006 modify it under the terms of the GNU Lesser General Public
00007 License as published by the Free Software Foundation; either
00008 version 2.1 of the License, or (at your option) any later version.
00009 
00010 This library is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 Lesser General Public License for more details.
00014 
00015 You should have received a copy of the GNU Lesser General Public
00016 License along with this library; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00018 
00019 A copy of the GNU Lesser General Public License has been provided with
00020 this library in the file 'COPYING'.
00021 
00022 Contact information for the author of this library has been provided
00023 with this library in the file 'AUTHOR'.
00024 ************************************************************************/
00025 #include "gui/cGuiCanvas.h"
00026 
00027 #include "GL/gl.h"
00028 
00029 #include "n2l/dynVars.h"
00030 #include "n2l/resourceManagement.h"
00031 
00032 #include "gui/cGuiFactory.h"
00033 
00034 #include <queue>
00035 using std::queue;
00036 
00037 namespace n2l
00038 {
00039 
00040 #   ifdef N2L_PASSIVE_GUI_REG
00041         tBool cGuiCanvas::smRegistered =
00042             cGuiFactory::current().registerLoader(
00043             "n2l::cGuiCanvas", cGuiElement::loadNew<cGuiCanvas> );
00044 #   endif
00045 
00046     /**************************************************************************/
00047     cGuiCanvas::cGuiCanvas() :
00048         cGuiElement(),
00049         mInnerOffset(0.0f,0.0f),
00050         mClipping(false),
00051         mEnabled(true)
00052     {
00053     }
00054 
00055     /**************************************************************************/
00056     cGuiCanvas::cGuiCanvas( const tGuiPos &iPos, const tGuiPos &iSize ) :
00057         cGuiElement(iPos,iSize),
00058         mInnerOffset(0.0f,0.0f),
00059         mClipping(false),
00060         mEnabled(true)
00061     {
00062     }
00063 
00064     /**************************************************************************/
00065     cGuiCanvas::cGuiCanvas( const cVfsNodeInterface &iNode ) :
00066         cGuiElement(),
00067         mInnerOffset(0.0f,0.0f),
00068         mClipping(false),
00069         mEnabled(true)
00070     {
00071         load( iNode );
00072     }
00073 
00074     /**************************************************************************/
00075     cGuiCanvas::cGuiCanvas( const cDynVar &iDefinition ) :
00076         cGuiElement(),
00077         mInnerOffset(0.0f,0.0f),
00078         mClipping(false),
00079         mEnabled(true)
00080     {
00081         load( iDefinition );
00082     }
00083 
00084     /**************************************************************************/
00085     cGuiCanvas::~cGuiCanvas()
00086     {
00087         // Do this so that children will be unlinked
00088         clear();
00089     }
00090 
00091     /**************************************************************************/
00092     void cGuiCanvas::load( const cVfsNodeInterface &iNode )
00093     {
00094         cDynVar def;
00095         validateAndDecode( def, iNode, "n2l::cGuiCanvas" );
00096         load( def );
00097     }
00098 
00099     /**************************************************************************/
00100     void cGuiCanvas::load( const cDynVar &iDefinition )
00101     {
00102         // Load parent properties
00103         cGuiElement::load( iDefinition );
00104 
00105         // Now my properties
00106         if (iDefinition.keyExists("members")) {
00107             cDynVar::tConstIterator pair( iDefinition["members"].begin() );
00108             const cDynVar::tConstIterator LastPair =
00109                 iDefinition["members"].end();
00110 
00111             for (;  pair!=LastPair; ++pair) {
00112                 if (!pair->second.isArray()) {
00113                     add( pair->first, cResourceManager::getGuiElement(
00114                         pair->second)->clone() );
00115                 } else {
00116                     tString name;
00117                     if (pair->second.keyExists("name"))
00118                         name = tString(pair->second["name"]);
00119                     else
00120                         name = pair->first;
00121                     if (pair->second.keyExists("type")) {
00122                         add( name, cGuiFactory::current().load(pair->second) );
00123                     } else {
00124                         add( name, cResourceManager::getGuiElement(
00125                             pair->second["file"])->clone() );
00126                     }
00127                 }
00128             } // For each pair
00129         }
00130 
00131         if (iDefinition["innerOffset"])
00132             innerOffset( tGuiPos( iDefinition["innerOffset"][0],
00133                 iDefinition["innerOffset"][1]) );
00134 
00135         if (iDefinition.keyExists("clipping"))
00136             clipping( iDefinition["clipping"] );
00137 
00138         enabled( iDefinition.keyValueOr("enabled",true) );
00139     }
00140 
00141     /**************************************************************************/
00142     void cGuiCanvas::add( const tGuiName &iName,
00143         const cAutoPtr<cGuiElement> &i_ioElement )
00144     {
00145         if (i_ioElement.dumbPtr() == this)
00146             throw cBadDataUseException( "cGuiCanvas::add",
00147                 "Added canvas to itself: \"" + iName + "\"" );
00148 
00149         const tUint NewID = mElements.size();
00150         tElementLookup::value_type newValue(iName,NewID);
00151         if (i_ioElement->canvas())
00152             throw cException( "cGuiCanvas::add", tString("Element: \"") +
00153                 iName + "\" already belongs to a canvas: " +
00154                 asString(tUint32(i_ioElement->canvas())) );
00155         i_ioElement->canvas( this );
00156         i_ioElement->name(iName);
00157         mElements.push_back(i_ioElement);
00158         mElementLookup.insert(newValue);
00159         if (i_ioElement->wantsFocus())
00160             mFocusOrder.push_back(i_ioElement);
00161 
00162         mRenderOrder[i_ioElement->renderOrder()].push_back( NewID );
00163     }
00164 
00165     /**************************************************************************/
00166     const cAutoPtr<cGuiElement> cGuiCanvas::remove( const tGuiName &iName )
00167     {
00168         cAutoPtr<cGuiElement> tmp = get( iName );
00169         if (!tmp.isSet())
00170             throw cOutOfBoundsException( "cGuiCanvas::remove",
00171                 "There is no such entity to remove in this canvas.",
00172                 iName );
00173 
00174         if (!tmp->canvas())
00175             throw cBadDataUseException( "cGuiCanvas::remove",
00176                 "The object requested was found but isn\'t in a canvas "
00177                 "which is really, really bad news." );
00178         
00179         tmp->canvas()->_real_remove( iName );
00180         tmp->canvas( 0 );
00181         return tmp;
00182     }
00183 
00184     /**************************************************************************/
00185     void cGuiCanvas::clipping( const tBool iClip )
00186     {
00187         mClipping = iClip;
00188     }
00189 
00190     /**************************************************************************/
00191     const tBool cGuiCanvas::clipping() const
00192     {
00193         return mClipping;
00194     }
00195 
00196     /**************************************************************************/
00197     void cGuiCanvas::innerOffset( const tGuiPos &iPos )
00198     {
00199         mInnerOffset = iPos;
00200     }
00201 
00202 
00203     /**************************************************************************/
00204     const tGuiPos &cGuiCanvas::innerOffset() const
00205     {
00206         return mInnerOffset;
00207     }
00208 
00209     /**************************************************************************/
00210     const cAutoPtr<cGuiElement> cGuiCanvas::get( const tGuiName &iName )
00211     {
00212         tElementLookup::iterator element( mElementLookup.find(iName) );
00213         if (element!=mElementLookup.end()) return mElements[element->second];
00214         
00215         // Scan through all the elements with children, and look in those
00216         for (tElementList::const_iterator it = mElements.begin();
00217             it!=mElements.end(); ++it)
00218         {
00219             const cAutoPtr<cGuiElement> elementPtr( (*it)->get(iName) );
00220             if (elementPtr.isSet()) return elementPtr;
00221         }
00222         return 0;
00223     }
00224 
00225     /**************************************************************************/
00226     cGuiElement::tOElementList cGuiCanvas::getByType( const type_info &iType )
00227     {
00228         tOElementList tmp;
00229         return getByType( tmp, iType );
00230     }
00231 
00232     /**************************************************************************/
00233     cGuiElement::tOElementList &cGuiCanvas::getByType( tOElementList &oList,
00234         const type_info &iType )
00235     {
00236         for (tElementList::const_iterator it = mElements.begin();
00237             it!=mElements.end(); ++it)
00238         {
00239             if (typeid(**it) == iType)
00240                 oList.push_back( *it );
00241 
00242             (*it)->getByType( oList, iType );
00243         }
00244         return oList;
00245         
00246     }
00247 
00248     /**************************************************************************/
00249     void cGuiCanvas::clear()
00250     {
00251         // Unlink all children
00252         for (tElementList::iterator eIt = mElements.begin();
00253             eIt!=mElements.end(); ++eIt)
00254         {
00255             (*eIt)->canvas(0);
00256         }
00257 
00258         // Empty our reference lists
00259         mElements.clear();
00260         mElementLookup.clear();
00261         mFocusOrder.clear();
00262         mRenderOrder.clear();
00263     }
00264 
00265     /**************************************************************************/
00266     void cGuiCanvas::draw() const
00267     {
00268         if (!enabled()) return;
00269         glPushMatrix();
00270         glPushAttrib( GL_ALL_ATTRIB_BITS );
00271         if (clipping()) {
00272             glDepthMask( true );
00273             glClearDepth(1.0f);
00274             glClear( GL_DEPTH_BUFFER_BIT );
00275             glEnable( GL_DEPTH_TEST );
00276             glColorMask( false,false,false,false );
00277             glDepthFunc( GL_ALWAYS );
00278             glBegin( GL_QUADS );
00279                 glVertex3f( innerPos().x(), innerPos().y(), 0 );
00280                 glVertex3f( innerPos().x()+innerSize().x(), innerPos().y(),
00281                     0 );
00282                 glVertex3f( innerPos().x()+innerSize().x(), innerPos().y() +
00283                     innerSize().y(), 0 );
00284                 glVertex3f( innerPos().x(),innerPos().y()+innerSize().y(), 0 );
00285             glEnd();
00286             glColorMask( true,true,true,true );
00287             glDepthMask( false );
00288             glDepthFunc( GL_EQUAL );
00289             outerPos().glTranslatef();
00290             innerOffset().glTranslatef();
00291 
00292             tGuiPos lrClip( outerSize() );
00293             lrClip -= innerOffset();
00294             tUint i = 0;
00295 
00296             const tRenderOrder::const_iterator LastRGroup = mRenderOrder.end();
00297             for (tRenderOrder::const_iterator rGroup = mRenderOrder.begin();
00298                 rGroup!=LastRGroup; ++rGroup)
00299             {
00300                 const tElementIDList::const_iterator LastE =
00301                     rGroup->second.end();
00302 
00303                 for (tElementIDList::const_iterator eIt =
00304                     rGroup->second.begin(); eIt!=LastE; ++eIt)
00305                 {
00306                     const cGuiElement &Element = *(mElements[*eIt]);
00307                     tGuiPos ulClip( Element.pos() );
00308                     ulClip += Element.size();
00309                     ulClip += innerOffset();
00310                     if (Element.pos().x()>lrClip.x() ||
00311                         Element.pos().y()>lrClip.y() ||
00312                         ulClip.x()<0 || ulClip.y()<0 ) {
00313                         ++i;
00314                         continue;
00315                     }
00316                     Element.draw();
00317                 }
00318             }
00319 
00320         } else {
00321             outerPos().glTranslatef();
00322             innerOffset().glTranslatef();
00323             const tRenderOrder::const_iterator LastRGroup = mRenderOrder.end();
00324             for (tRenderOrder::const_iterator rGroup = mRenderOrder.begin();
00325                 rGroup!=LastRGroup; ++rGroup)
00326             {
00327                 const tElementIDList::const_iterator LastE =
00328                     rGroup->second.end();
00329 
00330                 for (tElementIDList::const_iterator eIt =
00331                     rGroup->second.begin(); eIt!=LastE; ++eIt)
00332                 {
00333                     mElements[*eIt]->draw();
00334                 }
00335             }
00336         }
00337         glPopAttrib();
00338         glPopMatrix();
00339     }
00340 
00341     /**************************************************************************/
00342     void cGuiCanvas::systemEvent(
00343         const cAutoPtr<const cEventInterface> &i_iEvent )
00344     {
00345         if (!enabled()) return;
00346         cAutoPtr<const cEventInterface> modifedEvent;
00347         tBool inside( true );
00348         switch (i_iEvent->type())
00349         {
00350             //-----------------------------------------------
00351             // Warp the mouse location to this canvas
00352             case EventType_MouseButton: {
00353                 const cAutoPtr<const cMouseButtonEvent> Button( i_iEvent );
00354                 cMouseButtonEvent *tempEvent =
00355                     new cMouseButtonEvent( *Button );
00356                 tempEvent->pos( tempEvent->pos()-pos() );
00357                 // Are we still on the canvas?
00358                 if (clipping() && (
00359                     tempEvent->pos().x()<0 || 
00360                     tempEvent->pos().y()<0 ||
00361                     tempEvent->pos().x()>=outerSize().x() ||
00362                     tempEvent->pos().y()>=outerSize().y() ) )
00363                 {
00364                     // Outside, send this as an outside event instead.
00365                     inside = false;
00366                 }
00367                 tempEvent->pos( tempEvent->pos()-innerOffset() );
00368                 // Use the modified event
00369                 modifedEvent = tempEvent;
00370                 break;
00371             }
00372 
00373             //-----------------------------------------------
00374             // Warp the mouse location to this canvas
00375             case EventType_MouseMotion: {
00376                 const cAutoPtr<const cMouseMotionEvent> Motion( i_iEvent );
00377                 cMouseMotionEvent *tempEvent =
00378                     new cMouseMotionEvent( *Motion );
00379                 tempEvent->pos( tempEvent->pos()-pos() );
00380                 // Are we still on the canvas?
00381                 if (clipping() && (
00382                     tempEvent->pos().x()<0 || 
00383                     tempEvent->pos().y()<0 ||
00384                     tempEvent->pos().x()>=outerSize().x() ||
00385                     tempEvent->pos().y()>=outerSize().y() ) )
00386                 {
00387                     // Outside, send this as an outside event instead.
00388                     inside = false;
00389                 }
00390                 tempEvent->pos( tempEvent->pos()-innerOffset() );
00391                 // Use the modified event
00392                 modifedEvent = tempEvent;
00393                 break;
00394             }
00395 
00396             //-----------------------------------------------
00397             // We have to check for a focus change
00398             case EventType_Key: {
00399                 const cAutoPtr<const cKeyEvent> Key( i_iEvent );
00400                 if (Key->key()==Key_Tab && Key->pressed()) {
00401                     if (Key->mods()&KMod_Shift)
00402                         focusBack();
00403                     else
00404                         focusForward();
00405                 }
00406                 // And pass it along unmodifed
00407                 modifedEvent = i_iEvent;
00408                 break;
00409             }
00410                 
00411             //-----------------------------------------------
00412             // Nothing special to do, just pass it along
00413             default:
00414                 modifedEvent = i_iEvent;
00415                 break;
00416         }
00417 
00418         if (inside) {
00419             for (tElementList::iterator eIt = mElements.begin();
00420                 eIt!=mElements.end(); ++eIt)
00421                 (*eIt)->systemEvent( modifedEvent );
00422         } else {
00423             for (tElementList::iterator eIt = mElements.begin();
00424                 eIt!=mElements.end(); ++eIt)
00425                 (*eIt)->systemEventOutside( modifedEvent );
00426         }
00427     }
00428 
00429 
00430     /**************************************************************************/
00431     void cGuiCanvas::systemEventOutside(
00432         const cAutoPtr<const cEventInterface> &i_iEvent )
00433     {
00434         if (!enabled()) return;
00435         cAutoPtr<const cEventInterface> modifedEvent;
00436         switch (i_iEvent->type())
00437         {
00438             //-----------------------------------------------
00439             // Warp the mouse location to this canvas
00440             case EventType_MouseButton: {
00441                 const cAutoPtr<const cMouseButtonEvent> Button = i_iEvent;
00442                 cMouseButtonEvent *tempEvent =
00443                     new cMouseButtonEvent( *Button );
00444                 tempEvent->pos( (tempEvent->pos()-pos())-innerOffset() );
00445                 // Use the modified event
00446                 modifedEvent = tempEvent;
00447                 break;
00448             }
00449 
00450             //-----------------------------------------------
00451             // Warp the mouse location to this canvas
00452             case EventType_MouseMotion: {
00453                 const cAutoPtr<const cMouseMotionEvent> Motion = i_iEvent;
00454                 cMouseMotionEvent *tempEvent =
00455                     new cMouseMotionEvent( *Motion );
00456                 tempEvent->pos( (tempEvent->pos()-pos())-innerOffset() );
00457                 // Use the modified event
00458                 modifedEvent = tempEvent;
00459                 break;
00460             }
00461 
00462             //-----------------------------------------------
00463             // Nothing special to do, just pass it along
00464             default:
00465                 modifedEvent = i_iEvent;
00466                 break;
00467         }
00468         // Pass the event along
00469         for (tElementList::iterator eIt = mElements.begin();
00470             eIt!=mElements.end(); ++eIt)
00471             (*eIt)->systemEventOutside( modifedEvent );
00472     }
00473     
00474     /**************************************************************************/
00475     void cGuiCanvas::update( const tUint iTimePassed )
00476     {
00477         queue<tString> delNames;
00478         
00479         if (!enabled()) return;
00480         cGuiElement::update( iTimePassed );
00481         for (tElementList::iterator eIt = mElements.begin();
00482             eIt!=mElements.end(); ++eIt)
00483         {
00484             (*eIt)->update( iTimePassed );
00485             if ((*eIt)->suicidal()) delNames.push( (*eIt)->name() );
00486         }
00487 
00488         while (!delNames.empty()) {
00489             remove( delNames.front() );
00490             delNames.pop();
00491         }
00492     }
00493 
00494     /**************************************************************************/
00495     void cGuiCanvas::dropAllFocus( const cGuiElement *const ioFrom )
00496     {
00497         for (tElementList::iterator eIt = mElements.begin();
00498             eIt!=mElements.end(); ++eIt)
00499         {
00500             if (ioFrom!=eIt->dumbPtr())
00501                 (*eIt)->focus( false );
00502         }
00503         if (canvas())
00504             canvas()->dropAllFocus( this );
00505     }
00506 
00507     /**************************************************************************/
00508     void cGuiCanvas::focusForward()
00509     {
00510         const tElementFocusOrder::size_type ListSize = mFocusOrder.size();
00511         if (ListSize<2) return;
00512         tElementFocusOrder::size_type focusedIndex = 0;
00513         tBool found = false;
00514         while (focusedIndex!=ListSize && !found) {
00515             if (mFocusOrder[focusedIndex]->focus()) found=true;
00516             else ++focusedIndex;
00517         }
00518 
00519         if (focusedIndex==ListSize) {
00520             // Nothing had focus, so set the first and quit
00521             mFocusOrder[0]->focus(true);
00522             return;
00523         }
00524         // Do the switch
00525         mFocusOrder[focusedIndex]->focus(false);
00526         ++focusedIndex;
00527         if (focusedIndex==ListSize) focusedIndex = 0;
00528         mFocusOrder[focusedIndex]->focus(true);
00529     }
00530 
00531     /**************************************************************************/
00532     void cGuiCanvas::focusBack()
00533     {
00534         const tElementFocusOrder::size_type ListSize = mFocusOrder.size();
00535         if (ListSize<2) return;
00536         tElementFocusOrder::size_type focusedIndex = 0;
00537         tBool found = false;
00538         while (focusedIndex!=ListSize && !found) {
00539             if (mFocusOrder[focusedIndex]->focus()) found=true;
00540             else ++focusedIndex;
00541         }
00542 
00543         if (focusedIndex==ListSize) {
00544             // Nothing had focus, so set the first and quit
00545             mFocusOrder[0]->focus(true);
00546             return;
00547         }
00548         // Do the switch
00549         mFocusOrder[focusedIndex]->focus(false);
00550         if (focusedIndex==ListSize) focusedIndex = 0;
00551         else if (focusedIndex==0) focusedIndex = ListSize-1;
00552         else --focusedIndex;
00553         mFocusOrder[focusedIndex]->focus(true);
00554     }
00555 
00556 
00557     /**************************************************************************/
00558     const cAutoPtr<cGuiElement> cGuiCanvas::clone() const
00559     {
00560         cAutoPtr<cGuiElement> newElement( new cGuiCanvas );
00561         cloneInto( newElement );
00562         return newElement;
00563     }
00564 
00565     /**************************************************************************/
00566     void cGuiCanvas::cloneInto( const cAutoPtr<cGuiCanvas> &i_ioElement ) const
00567     {
00568         // Parent Properties first
00569         cGuiElement::cloneInto( i_ioElement );
00570 
00571         for (tElementList::const_iterator eIt = mElements.begin();
00572             eIt!=mElements.end(); ++eIt)
00573                 i_ioElement->add( (*eIt)->name(), (*eIt)->clone() );
00574         i_ioElement->innerOffset( innerOffset() );
00575         i_ioElement->clipping( clipping() );
00576         i_ioElement->enabled( enabled() );
00577     }
00578 
00579     /**************************************************************************/
00580     const tBool cGuiCanvas::hasChildren() const
00581     {
00582         return true;
00583     }
00584 
00585     /**************************************************************************/
00586     void cGuiCanvas::enabled( const tBool iEnabled )
00587     {
00588         mEnabled = iEnabled;
00589     }
00590 
00591     /**************************************************************************/
00592     void cGuiCanvas::prop( const tString &iName, const cDynVar &iVal,
00593         const tString &iInnerKey )
00594     {
00595         if (iName == "enabled") 
00596             enabled( iVal );
00597 
00598         else cGuiElement::prop( iName, iVal );
00599     }
00600 
00601     /**************************************************************************/
00602     const cDynVar cGuiCanvas::prop( const tString &iName,
00603         const tString &iInnerKey ) const
00604     {
00605         if (iName == "enabled")
00606             return enabled();
00607 
00608         return cGuiElement::prop( iName );
00609     }
00610 
00611     /**************************************************************************/
00612     void cGuiCanvas::_real_remove( const tGuiName &iName )
00613     {
00614         // This is punishment for something, I'm just not sure what.
00615         cAutoPtr<cGuiElement> toBeDel = get(iName);
00616         tUint eID;
00617         {
00618             tElementLookup::iterator tmp = mElementLookup.find(iName);
00619             if (tmp == mElementLookup.end())
00620                 throw cOutOfBoundsException( "cGuiCanvas::_real_remove",
00621                     "I have no idea how this happened.  Sorry." );
00622             eID = tmp->second;
00623             mElementLookup.erase( tmp );
00624         }
00625 
00626         // It may very well not be included here.  That's fine.
00627         for (tElementFocusOrder::iterator i = mFocusOrder.begin();
00628             i!=mFocusOrder.end(); )
00629         {
00630             if (*i == toBeDel) i = mFocusOrder.erase( i );
00631             else ++i;
00632         }
00633 
00634         mElements.erase( tElementList::iterator(&(mElements[eID])) );
00635 
00636         // Drop all tElementLookup types by one if larger than eID.
00637         for (tElementLookup::iterator i = mElementLookup.begin(); 
00638             i!=mElementLookup.end(); ++i)
00639         {
00640             if (i->second>eID) --(i->second);
00641         }
00642 
00643         // Drop all tElementIDList types by one if larger than eID.
00644         for (tRenderOrder::iterator i = mRenderOrder.begin(); 
00645             i!=mRenderOrder.end(); ++i)
00646         {
00647             for (tElementIDList::iterator i2 = i->second.begin();
00648                 i2!=i->second.end();)
00649             {
00650                 if (*i2==eID) i2 = i->second.erase(i2);
00651                 else ++i2;
00652             }
00653             for (tElementIDList::iterator i2 = i->second.begin();
00654                 i2!=i->second.end(); ++i2)
00655             {
00656                 if (*i2>eID) --(*i2);
00657             }
00658         }
00659     }
00660 
00661 } // namespace n2l
©2012 Aaron Cameron