![[]](/images/special/trans.gif)
LibN2L-4 Library Code ReferenceClassesCompounds Files Members Method Index Full Reference cGuiElement.cppGo 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 |