AaronCameron.net
No ads. No Profit. No Master, But Truth.
Not a Member? - Login or Create an Account
Sunday the 20th of May 2012 @ 04:45pm
Front Page Journal Projects Your Profile About
[]

LibN2L-4 Library Code Reference

Classes
Compounds
Files
Members
Method Index
Full Reference

cGuiElement.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/cGuiElement.h"
00026 
00027 #include "n2l/vfs.h"
00028 #include "n2l/dynVars.h"
00029 
00030 #include "n2l/events.h"
00031 
00032 #include "gui/cGuiCanvas.h"
00033 #include "gui/cGuiFactory.h"
00034 
00035 #include "gui/cGuiACInt.h"
00036 #include "gui/cGuiSEInt.h"
00037 
00038 #include "gui/cGuiACFactory.h"
00039 
00040 namespace n2l
00041 {
00042 
00043     tUint cGuiElement::smNextElementNumber =    0;
00044     
00045     const tActionBindingID  cGuiElement::FirstSystemActionID( 0 );
00046     const tActionBindingID  cGuiElement::FirstUserActionID( 1000 );
00047 
00048     /**************************************************************************/
00049     cGuiElement::cGuiElement() :
00050         mPos(0.0f,0.0f),
00051         mSize(0.0f,0.0f),
00052         mTopLeftPadding(0.0f,0.0f),
00053         mBottomRightPadding(0.0f,0.0f),
00054         mHasFocus(false),
00055         mName("Element "),
00056         mRenderOrder(0),
00057         mMyCanvas(0),
00058         mNextSystemActionID( FirstSystemActionID ),
00059         mNextUserActionID( FirstUserActionID ),
00060         mFirstUpdateDone(false),
00061         mSuicide(false)
00062     {
00063         mName += asString(nextElementNumber());
00064         // Force call our own, since any children classes haven't
00065         // been constructed yet, and this could play havoc with 
00066         // their members.
00067         cGuiElement::dimensionChanged();
00068     }
00069 
00070     /**************************************************************************/
00071     cGuiElement::cGuiElement( const tGuiPos &iPos, const tGuiPos &iSize,
00072         const tString &iName ) :
00073         mPos(iPos),
00074         mSize(iSize),
00075         mHasFocus(false),
00076         mName(iName),
00077         mRenderOrder(0),
00078         mMyCanvas(0),
00079         mNextSystemActionID( FirstSystemActionID ),
00080         mNextUserActionID( FirstUserActionID ),
00081         mFirstUpdateDone(false),
00082         mSuicide(false)
00083     {
00084         if (mName.empty()) {
00085             mName = "Element ";
00086             mName += asString(nextElementNumber());
00087         }
00088         dimensionChanged();
00089     }
00090 
00091     /**************************************************************************/
00092     cGuiElement::~cGuiElement()
00093     {
00094     }
00095 
00096     /**************************************************************************/
00097     void cGuiElement::load( const cVfsNodeInterface &iNode )
00098     {
00099         cDynVar def;
00100         validateAndDecode( def, iNode, "n2l::cGuiElement" );
00101         load(def);
00102     }
00103 
00104     /**************************************************************************/
00105     void cGuiElement::load( const cDynVar &iDef )
00106     {
00107         if (iDef["pos"])
00108             pos( tGuiPos( iDef["pos"][0],iDef["pos"][1] ) );
00109 
00110         if (iDef["size"])
00111             size( tGuiPos( iDef["size"][0],iDef["size"][1] ) );
00112 
00113         if (iDef.keyExistsAsArray("padding") && iDef["padding"].size()==2) {
00114             padding( tGuiPos( iDef["padding"][0][0],
00115                 iDef["padding"][0][1] ), tGuiPos( iDef["padding"][1][0],
00116                 iDef["padding"][1][1] ) );
00117 
00118         } else if (iDef.keyExistsAsArray("padding")) {
00119             padding( tGuiPos(iDef["padding"][0],iDef["padding"][1] ),
00120                 tGuiPos(iDef["padding"][2],iDef["padding"][3] ) );
00121 
00122         } else if (iDef.keyExists("padding")) {
00123             const tFloat Padding = iDef["padding"];
00124             padding( tGuiPos(Padding,Padding), tGuiPos(Padding,Padding) );
00125         }       
00126 
00127         renderOrder( iDef.keyValueOr( "renderOrder", 0 ) );
00128 
00129         if (iDef.keyExistsAsArray("actions")) {
00130             const cDynVar::tConstIterator Last = iDef["actions"].end();
00131             for (cDynVar::tConstIterator i = iDef["actions"].begin();
00132                 i!=Last; ++i)
00133             {
00134                 boundCheckActionType(asUint(i->first));
00135                 bindUserAction( tGuiActionType(asUint(i->first)), 
00136                     cGuiACFactory::current().load( i->second ) );
00137             }
00138         }
00139     }
00140 
00141     /**************************************************************************/
00142     const cAutoPtr<cGuiElement> cGuiElement::get( const tGuiName &iName )
00143     {
00144         return 0;
00145     }
00146 
00147     /**************************************************************************/
00148     const cAutoPtr<cGuiElement> cGuiElement::mustGet( const tGuiName &iName )
00149     {
00150         const cAutoPtr<cGuiElement> Element( get(iName) );
00151         if (!Element.isSet())
00152             throw cOutOfBoundsException("cGuiElement::mustGet",
00153                 tString("Failed to find required element: \"") +
00154                 iName + "\"");
00155         return Element;
00156     }
00157 
00158     /**************************************************************************/
00159     const tGuiPos & cGuiElement::pos() const
00160     {
00161         return mPos;
00162     }
00163 
00164     /**************************************************************************/
00165     const tGuiPos & cGuiElement::size() const
00166     {
00167         return mSize;
00168     }
00169 
00170     /**************************************************************************/
00171     const tGuiPos & cGuiElement::topLeftPadding() const
00172     {
00173         return mTopLeftPadding;
00174     }
00175 
00176 
00177     /**************************************************************************/
00178     const tGuiPos & cGuiElement::bottomRightPadding() const
00179     {
00180         return mBottomRightPadding;
00181     }
00182 
00183     /**************************************************************************/
00184     const tString & cGuiElement::name() const
00185     {
00186         return mName;
00187     }
00188 
00189     /**************************************************************************/
00190     void cGuiElement::renderOrder( const tSint iOrder )
00191     {
00192         if (mMyCanvas)
00193             throw cUnsupportedMethodException( "cGuiElement::renderOrder",
00194                 "Unable to change render order after being added to a "
00195                 "canvas.  FIX ME!" );
00196         mRenderOrder = iOrder;
00197     }
00198 
00199     /**************************************************************************/
00200     const tSint &cGuiElement::renderOrder() const
00201     {
00202         return mRenderOrder;
00203     }
00204 
00205     /**************************************************************************/
00206     void cGuiElement::prop( const tString &iName, const cDynVar &iVal,
00207         const tString &iInnerKey )
00208     {
00209         if (iName == "pos") 
00210             pos( tGuiPos( iVal[0],iVal[1] ) );
00211 
00212         else if (iName == "size")
00213             size( tGuiPos( iVal[0],iVal[1] ) );
00214 
00215         else if (iName == "padding") {
00216             if (iVal.isArray() && iVal["padding"].size()==2) {
00217                 padding( tGuiPos( iVal[0][0], iVal[0][1] ),
00218                     tGuiPos( iVal[1][0], iVal[1][1] ) );
00219 
00220             } else if (iVal.isArray()) {
00221                 padding( tGuiPos(iVal[0],iVal[1] ),
00222                     tGuiPos(iVal[2],iVal[3] ) );
00223 
00224             } else {
00225                 const tFloat Padding = iVal["padding"];
00226                 padding( tGuiPos(Padding,Padding),
00227                     tGuiPos(Padding,Padding) );
00228             }
00229 
00230         } else if ( iName == "renderOrder" )
00231             renderOrder( iVal );
00232     }
00233 
00234     /**************************************************************************/
00235     const cDynVar cGuiElement::prop( const tString &iName,
00236         const tString &iInnerKey ) const
00237     {
00238         cDynVar oVal = cDynVar::Null;
00239         
00240         if (iName == "name") 
00241             oVal = mName;
00242 
00243         else if (iName == "size") {
00244             oVal = cDynVar::Array;
00245             oVal[0] = size().x();
00246             oVal[1] = size().y();
00247 
00248         } else if (iName == "padding") {
00249             oVal = cDynVar::Array;
00250             oVal[0] = topLeftPadding().x();
00251             oVal[1] = topLeftPadding().y();
00252             oVal[2] = bottomRightPadding().x();
00253             oVal[3] = bottomRightPadding().y();
00254 
00255         } else if ( iName == "renderOrder" )
00256             oVal = renderOrder();
00257 
00258         return oVal;
00259     }
00260 
00261     /**************************************************************************/
00262     void cGuiElement::pos( const tGuiPos & iPos )
00263     {
00264         if (mPos!=iPos) {
00265             mPos = iPos;
00266             dimensionChanged();
00267         }
00268     }
00269 
00270     /**************************************************************************/
00271     void cGuiElement::size( const tGuiPos &iSize )
00272     {
00273         mSize = iSize;
00274         dimensionChanged();
00275     }
00276 
00277 
00278     /**************************************************************************/
00279     void cGuiElement::padding(  const tGuiPos &iTopLeft,
00280         const tGuiPos &iBottomRight )
00281     {
00282         mTopLeftPadding = iTopLeft;
00283         mBottomRightPadding = iBottomRight;
00284         dimensionChanged();
00285     }
00286 
00287 
00288     /**************************************************************************/
00289     void cGuiElement::name( const tString &iName )
00290     {
00291         mName = iName;
00292         stateChanged();
00293     }
00294 
00295     /**************************************************************************/
00296     void cGuiElement::systemEvent(
00297         const cAutoPtr<const cEventInterface> &i_Event )
00298     {
00299     }
00300 
00301     /**************************************************************************/
00302     void cGuiElement::systemEventOutside(
00303         const cAutoPtr<const cEventInterface> &i_Event )
00304     {
00305     }
00306 
00307     /**************************************************************************/
00308     void cGuiElement::update( const tUint iTimePassed )
00309     {
00310         if (!mFirstUpdateDone) {
00311             cDynVar data = cDynVar::Array;
00312             data.insert( "name", name() );
00313             broadcastAction( GuiActionType_FirstUpdate, data );
00314             mFirstUpdateDone = true;
00315         }
00316 
00317         tSpecialEffectContainer::iterator effect( mEffects.begin() );
00318         while (effect!=mEffects.end())
00319         {
00320             if (!(*effect)->actOn(this,iTimePassed)) {
00321                 // Send an event that the effect is complete
00322                 tActionData actionData( tActionData::Array );
00323                 actionData.insert("effectName",(*effect)->name());
00324                 broadcastAction( GuiActionType_EffectComplete, actionData );
00325 #               ifdef N2L_SLOPPY_SE_ALIVE_STATUS
00326                     (*effect)->alive( false );
00327 #               else
00328                     if ((*effect)->alive()!=false)
00329                         throw cUnsupportedMethodException(
00330                             "cGuiElement::update", "Special effect called \""
00331                             + effect->name() + "\" didn\'t set its alive "
00332                             "status properly." );
00333 #               endif
00334                 // Remove it.
00335                 effect = mEffects.erase(effect);
00336             } else
00337                 ++effect;
00338         }
00339     }
00340 
00341     /**************************************************************************/
00342     void cGuiElement::draw() const
00343     {
00344     }
00345 
00346     /**************************************************************************/
00347     cGuiElement::tOElementList cGuiElement::getByType( const type_info &iType )
00348     {
00349         tOElementList tmp;
00350         return getByType( tmp, iType );
00351     }
00352 
00353     /**************************************************************************/
00354     cGuiElement::tOElementList &cGuiElement::getByType( tOElementList &oList,
00355         const type_info &iType )
00356     {
00357         return oList;
00358     }
00359 
00360     /**************************************************************************/
00361     const tBool cGuiElement::focus() const
00362     {
00363         return mHasFocus;
00364     }
00365 
00366     /**************************************************************************/
00367     void cGuiElement::focus( const tBool iFocus )
00368     {
00369         if (iFocus==mHasFocus) return;
00370         if (canvas() && iFocus) canvas()->dropAllFocus( this );
00371         mHasFocus = iFocus;
00372         stateChanged();
00373     }
00374 
00375     /**************************************************************************/
00376     const tBool cGuiElement::wantsFocus() const
00377     {
00378         return false;
00379     }
00380 
00381     /**************************************************************************/
00382     const tUint cGuiElement::nextElementNumber()
00383     {
00384         return smNextElementNumber++;
00385     }
00386 
00387     /**************************************************************************/
00388     void cGuiElement::canvas( cGuiCanvas *const iCanvas )
00389     {
00390         mMyCanvas = iCanvas;
00391     }
00392 
00393     /**************************************************************************/
00394     cGuiCanvas *const cGuiElement::canvas()
00395     {
00396         return mMyCanvas;
00397     }
00398 
00399     /**************************************************************************/
00400     void cGuiElement::dimensionChanged()
00401     {
00402         mInnerPos = mPos+mTopLeftPadding;
00403         mInnerSize = mSize-mTopLeftPadding-mBottomRightPadding;
00404     }
00405 
00406     /**************************************************************************/
00407     void cGuiElement::stateChanged()
00408     {
00409     }
00410 
00411     /**************************************************************************/
00412     void cGuiElement::propertyChanged()
00413     {
00414     }
00415 
00416     /**************************************************************************/
00417     void cGuiElement::cloneInto( 
00418         const cAutoPtr<cGuiElement> &i_ioElement ) const
00419     {
00420         i_ioElement->name( name() );
00421         i_ioElement->pos( pos() );
00422         i_ioElement->size( size() );
00423         i_ioElement->renderOrder( renderOrder() );
00424         i_ioElement->padding( topLeftPadding(),bottomRightPadding() );
00425 
00426         // Clone across  actions
00427         for (tUint i = 0; i<GuiActionType_NumActionTypes; i++) {
00428             const tActionList::const_iterator Last = mActions[i].end();
00429             for (tActionList::const_iterator i2 = mActions[i].begin();
00430                 i2!=Last; ++i2)
00431             {
00432                 if (i2->first>=FirstUserActionID)
00433                     i_ioElement->bindUserAction( tGuiActionType(i),
00434                         i2->second->clone() );
00435             }
00436         }
00437     }
00438 
00439     /**************************************************************************/
00440     void cGuiElement::validateAndDecode( cDynVar &oDefinition,
00441         const cVfsNodeInterface &iNode, const tString &iRequiredHeader )
00442     {
00443         if (!iNode.likeFile())
00444             throw cBadDataUseException( "cGuiElement::validateAndDecode",
00445                 "Provided node isn\'t like a file" );
00446         // Load it.
00447         if (iNode.firstLine()!=iRequiredHeader)
00448             throw cParsingException("cGuiElement::validateAndDecode",
00449                 tString("This file isn\'t the right type.  Wanted: ") +
00450                     iRequiredHeader + " got: " + iNode.firstLine() );
00451 
00452         if (iNode.buffer().size()<=(iNode.firstLine().size()+1))
00453             throw cParsingException("cGuiElement::validateAndDecode",
00454                 "No data after header" );
00455 
00456         // The type is ok, unserialize it for the caller to work with.
00457         oDefinition.unserialize( iNode.buffer().c_str() +
00458             iNode.firstLine().size()+1 );
00459     }
00460 
00461     /**************************************************************************/
00462     const tBool cGuiElement::hasChildren() const
00463     {
00464         return false;
00465     }
00466 
00467     /**************************************************************************/
00468     void cGuiElement::addEffect(
00469         const cAutoPtr<cGuiSEInt> &i_ioEffect )
00470     {
00471         mEffects.push_back( i_ioEffect );
00472     }
00473 
00474     /**************************************************************************/
00475     void cGuiElement::clearEffects()
00476     {
00477         tSpecialEffectContainer::iterator effect( mEffects.begin() );
00478         while (effect!=mEffects.end())
00479         {
00480             (*effect)->alive(false);
00481             ++effect;
00482         }
00483     }
00484 
00485     /**************************************************************************/
00486     const tUint cGuiElement::numEffects() const
00487     {
00488         return mEffects.size();
00489     }
00490 
00491     /**************************************************************************/
00492     const tActionBindingID  cGuiElement::bindUserAction(
00493         const tGuiActionType iType,
00494         const cAutoPtr<cGuiACInt> &i_ioAction )
00495     {
00496         return bindAction( iType, i_ioAction, true );
00497     }
00498 
00499     /**************************************************************************/
00500     void cGuiElement::unbindUserAction( const tActionBindingID iID )
00501     {
00502         unbindAction( iID, true );
00503     }
00504 
00505     /**************************************************************************/
00506     void cGuiElement::clearUserActions()
00507     {
00508         for (tUint a=0; a<GuiActionType_NumActionTypes; ++a) {
00509             tActionList::iterator aIT = mActions[a].begin();
00510             while (aIT!=mActions[a].end()) {
00511                 tActionList::iterator nextIT = aIT;
00512                 ++nextIT;
00513                 if (aIT->first>=FirstUserActionID)
00514                     mActions[a].erase( aIT );
00515                 aIT = nextIT;
00516             }
00517         }
00518     }
00519 
00520     /**************************************************************************/
00521     const tActionBindingID  cGuiElement::bindAction(
00522         const tGuiActionType iType,
00523         const cAutoPtr<cGuiACInt> &i_ioAction,
00524         const tBool iUser )
00525     {
00526         if (iType<0 || iType>=GuiActionType_NumActionTypes)
00527             throw cOutOfBoundsException("cGuiElement::bindAction",
00528                 tString("No Such action type: ") + asString(tUint(iType)) );
00529         tActionBindingID newID;
00530         if (iUser)
00531             newID = mNextUserActionID++;
00532         else
00533             newID = mNextSystemActionID++;
00534 
00535         tActionList::value_type newAction( newID, i_ioAction );
00536         mActions[iType].insert( newAction );
00537         return newID;
00538     }
00539 
00540 
00541     /**************************************************************************/
00542     void cGuiElement::unbindAction( const tActionBindingID iID,
00543         const tBool iUser )
00544     {
00545         if (iUser && iID<FirstUserActionID)
00546             throw cOutOfBoundsException( "cGuiElement::unbindAction",
00547                 tString("May not unbind system actions: ")+
00548                 asString(tUint(iID)) );
00549         
00550         // Check to make sure the action exists
00551         for (tUint i=GuiActionType_None; i<GuiActionType_NumActionTypes; ++i) {
00552             const tActionList::iterator ActionIT( mActions[i].find(iID) );
00553             if (ActionIT!=mActions[i].end()) {
00554                 // Unbind it and be done with the stupid thing.
00555                 mActions[i].erase( ActionIT );
00556                 return;
00557             }
00558         }
00559         throw cOutOfBoundsException( "cGuiElement::unbindAction",
00560             tString("No such action ID to unbind: ") + asString(tUint(iID)) );
00561     }
00562 
00563     /**************************************************************************/
00564     void cGuiElement::broadcastAction( const tGuiActionType iType,
00565         const tActionData & iData )
00566     {
00567         if (iType<0 || iType>=GuiActionType_NumActionTypes)
00568             throw cOutOfBoundsException( "cGuiElement::bindAction",
00569                 tString("No Such action type: ") + asString(tUint(iType)) );
00570 
00571         const tActionList::iterator EndActionIT( mActions[iType].end() );
00572         tActionList::iterator it = mActions[iType].begin();
00573         
00574         while (it!=EndActionIT)
00575         {
00576             tActionList::iterator nextIT( it );
00577             ++nextIT;
00578             it->second->execute( this, iType, iData );
00579             if (!it->second->preserveAction()) mActions[iType].erase(it);
00580             it = nextIT;
00581         }
00582     }
00583 
00584     /**************************************************************************/
00585     void cGuiElement::boundCheckActionType( const tUint &iType ) const
00586     {
00587         if (iType<=GuiActionType_None || iType>=GuiActionType_NumActionTypes)
00588             throw cOutOfBoundsException(
00589                 "cGuiInteractive::boundCheckActionType",
00590                 "Provided action type is out of bounds.", asString(iType) );
00591     }
00592 
00593 } // namespace n2l
©2012 Aaron Cameron