![[]](/images/special/trans.gif)
LibN2L-4 Library Code ReferenceClassesCompounds Files Members Method Index Full Reference cGuiButtonSelectBox.cppGo to the documentation of this file.00001 /************************************************************************ 00002 Nova-2 Library (libN2L, or simply n2l) Game development C++ Library 00003 Copyright (C) 2002 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/cGuiButtonSelectBox.h" 00026 00027 #include "n2l/vfs.h" 00028 #include "n2l/dynVars.h" 00029 #include "n2l/resourceManagement.h" 00030 00031 #include "gui/cGuiCanvas.h" 00032 #include "gui/cGuiSlider.h" 00033 #include "gui/cGuiButton.h" 00034 #include "gui/cGuiSimpleCallbackAction.h" 00035 #include "gui/cGuiSEInt.h" 00036 00037 #include "gui/cGuiFactory.h" 00038 00039 /******************************************************************************/ 00040 namespace n2l 00041 { 00042 00043 # ifdef N2L_PASSIVE_GUI_REG 00044 tBool cGuiButtonSelectBox::smRegistered = 00045 cGuiFactory::current().registerLoader( "n2l::cGuiButtonSelectBox", 00046 cGuiElement::loadNew<cGuiButtonSelectBox> ); 00047 # endif 00048 00049 const tUint cGuiButtonSelectBox::NoSelection( tUint(-1) ); 00050 00051 /**************************************************************************/ 00052 cGuiButtonSelectBox::cGuiButtonSelectBox() 00053 { 00054 reset(); 00055 } 00056 00057 /**************************************************************************/ 00058 cGuiButtonSelectBox::cGuiButtonSelectBox( const cVfsNodeInterface &iNode ) 00059 { 00060 reset(); 00061 load( iNode ); 00062 } 00063 00064 /**************************************************************************/ 00065 cGuiButtonSelectBox::cGuiButtonSelectBox( const cDynVar &iDefinition ) 00066 { 00067 reset(); 00068 load( iDefinition ); 00069 } 00070 00071 /**************************************************************************/ 00072 cGuiButtonSelectBox::~cGuiButtonSelectBox() 00073 { 00074 } 00075 00076 /**************************************************************************/ 00077 void cGuiButtonSelectBox::load( const cVfsNodeInterface &iNode ) 00078 { 00079 cDynVar def; 00080 validateAndDecode( def, iNode, "n2l::cGuiButtonSelectBox" ); 00081 load( def ); 00082 } 00083 00084 /**************************************************************************/ 00085 void cGuiButtonSelectBox::load( const cDynVar &iDefinition ) 00086 { 00087 // Parent definitions 00088 cGuiInteractive::load( iDefinition ); 00089 00090 // Our definitions 00091 if (iDefinition.keyExists("multiple")) 00092 multiple( tSint(iDefinition["multiple"]) ); 00093 00094 // Get a template for the slider 00095 if (iDefinition.keyExists("slider")) { 00096 if (iDefinition["slider"].isArray()) 00097 slider( cGuiSlider(iDefinition["slider"]) ); 00098 else { 00099 // Cleanly catch bad casts so we can show an error, instead 00100 // of just exploding anonymously. 00101 try { 00102 const cAutoPtr<const cGuiSlider> Slider( 00103 cResourceManager::getGuiElement(iDefinition["slider"])); 00104 slider( *Slider ); 00105 } 00106 catch (const cBadCastException & iException) { 00107 throw cParsingException( "cGuiButtonSelectBox::load", 00108 "Provided slider template file didn\'t " 00109 "define a slider"); 00110 } 00111 } 00112 } // slider was an array 00113 00114 // Check for buttons (This is super inefficient right now, 00115 // about 60% of these lookups could be removed) 00116 if (iDefinition.keyExists("buttons")) { 00117 const cDynVar::tConstIterator BEnd = iDefinition["buttons"].end(); 00118 for (cDynVar::tConstIterator b=iDefinition["buttons"].begin(); 00119 b!=BEnd; ++b) 00120 { 00121 cAutoPtr<const cGuiButton> Template; 00122 if (b->second["button"].isArray()) 00123 Template = new cGuiButton( b->second["button"] ); 00124 else { 00125 try { 00126 Template = cResourceManager::getGuiElement( 00127 b->second["button"]); 00128 } 00129 catch (const cBadCastException & iException) 00130 { 00131 throw cParsingException( "cGuiButtonSelectBox::load", 00132 "Provided slider template file didn\'t " 00133 "define a slider"); 00134 } 00135 } 00136 addButton( b->second["value"], b->second["label"], *Template ); 00137 } 00138 } 00139 00140 if (iDefinition.keyExists("selected")) 00141 selected( iDefinition["selected"] ); 00142 00143 if (iDefinition.keyExists("noUnselect")) 00144 noUnselect( iDefinition["noUnselect"] ); 00145 00146 } 00147 00148 /**************************************************************************/ 00149 void cGuiButtonSelectBox::draw() const 00150 { 00151 // Set the clipped canvas offset position if we should, 00152 // and draw the slider 00153 if (mSlider.isSet()) { 00154 mButtonsCanvas->innerOffset( tGuiPos(0.0f,-mSlider->value()) ); 00155 mSlider->draw(); 00156 } else { 00157 mButtonsCanvas->innerOffset( tGuiPos(0.0f,-mAltOffset) ); 00158 } 00159 00160 // Draw the clipped canvas 00161 mButtonsCanvas->draw(); 00162 } 00163 00164 /**************************************************************************/ 00165 void cGuiButtonSelectBox::slider( const cGuiSlider &iSliderTemplate ) 00166 { 00167 mSlider = iSliderTemplate.clone(); 00168 // Down on the wheel and kp should go deeper into the list 00169 mSlider->swapWheel( true ); 00170 dimensionChanged(); 00171 } 00172 00173 /**************************************************************************/ 00174 void cGuiButtonSelectBox::addButton( const cDynVar & iValue, 00175 const tString &iLabel, const cGuiButton &iButtonTemplate ) 00176 { 00177 // Create the button from the template 00178 cAutoPtr<cGuiButton> newButton( iButtonTemplate.clone() ); 00179 00180 if (!iLabel.empty()) 00181 newButton->label( iLabel ); 00182 newButton->type( cGuiButton::Type_Toggle ); 00183 newButton->toggledOn( false ); 00184 newButton->pos(mNextButtonPos); 00185 newButton->bindAction( GuiActionType_Clicked, 00186 new cGuiButtonSelectBox::cItemSelectedAction( this, iValue ), 00187 false ); 00188 mNextButtonPos.y() += newButton->size().y(); 00189 00190 // Add the value and buttons to our local containers 00191 mButtons.push_back( newButton ); 00192 mValues.push_back( iValue ); 00193 // We should have a more intelligent way of naming this. 00194 mButtonsCanvas->add( iLabel, newButton ); 00195 00196 // Update the slider to contain the correct number of values 00197 if (mSlider.isSet()) { 00198 mSlider->min(0.0f); 00199 mSlider->max(mNextButtonPos.y()); 00200 } 00201 } 00202 00203 /**************************************************************************/ 00204 void cGuiButtonSelectBox::multiple( const tBool iMultiple ) 00205 { 00206 mMultiple = iMultiple; 00207 } 00208 00209 /**************************************************************************/ 00210 const tBool cGuiButtonSelectBox::multiple() const 00211 { 00212 return mMultiple; 00213 } 00214 00215 /**************************************************************************/ 00216 void cGuiButtonSelectBox::noUnselect( const tBool iNoUnselect ) 00217 { 00218 mNoUnselect = iNoUnselect; 00219 } 00220 00221 /**************************************************************************/ 00222 const tBool cGuiButtonSelectBox::noUnselect() const 00223 { 00224 return mNoUnselect; 00225 } 00226 00227 /**************************************************************************/ 00228 const tUint cGuiButtonSelectBox::numButtons() const 00229 { 00230 return mButtons.size(); 00231 } 00232 00233 /**************************************************************************/ 00234 void cGuiButtonSelectBox::systemEvent( 00235 const cAutoPtr<const cEventInterface> &i_iEvent ) 00236 { 00237 cGuiInteractive::systemEvent( i_iEvent ); 00238 00239 if (i_iEvent->type()==EventType_MouseButton) 00240 { 00241 const cAutoPtr<const cMouseButtonEvent> Click( i_iEvent ); 00242 if (Click->pressed() && isOver()) focus(true); 00243 // Intercept up and down clicks and send them to the 00244 // slider instead of the canvas so that the wheel works 00245 // anywhere on the widget, rather than just on the 00246 // slide bar 00247 if ((Click->button()==MouseButton_Up || 00248 Click->button()==MouseButton_Down) && 00249 collides( Click->pos() ) ) 00250 { 00251 if (mSlider.isSet()) { 00252 cAutoPtr<cMouseButtonEvent> fakeClick( 00253 new cMouseButtonEvent(*Click) ); 00254 fakeClick->pos( mSlider->pos() ); 00255 mSlider->systemEvent( fakeClick ); 00256 } 00257 } else { 00258 // Slider is in here so we don't double send to it if 00259 // the up or down wheel is used. 00260 if (mSlider.isSet()) mSlider->systemEvent( i_iEvent ); 00261 mButtonsCanvas->systemEvent( i_iEvent ); 00262 } 00263 } else {// if this is a mouse button. 00264 if (mSlider.isSet()) mSlider->systemEvent( i_iEvent ); 00265 mButtonsCanvas->systemEvent( i_iEvent ); 00266 } 00267 00268 } 00269 00270 /**************************************************************************/ 00271 void cGuiButtonSelectBox::systemEventOutside( 00272 const cAutoPtr<const cEventInterface> &i_iEvent ) 00273 { 00274 cGuiInteractive::systemEventOutside( i_iEvent ); 00275 mButtonsCanvas->systemEventOutside( i_iEvent ); 00276 if (mSlider.isSet()) mSlider->systemEventOutside( i_iEvent ); 00277 } 00278 00279 00280 /**************************************************************************/ 00281 void cGuiButtonSelectBox::clearSelections() 00282 { 00283 if (mMultiple) { 00284 for (tUint i=0; i!=mButtons.size(); ++i) 00285 if (mButtons[i]->toggledOn()) { 00286 mButtons[i]->toggledOn( false ); 00287 broadcastUnselected(i); 00288 } 00289 } else { 00290 if (mButtons.size() > mSelected) { 00291 mButtons[mSelected]->toggledOn( false ); 00292 broadcastUnselected(mSelected); 00293 } 00294 mSelected = NoSelection; 00295 } 00296 } 00297 00298 /**************************************************************************/ 00299 void cGuiButtonSelectBox::clearButtons() 00300 { 00301 mSelected = NoSelection; 00302 mNextButtonPos.set(0.0f,0.0f); 00303 mValues.clear(); 00304 mButtons.clear(); 00305 mButtonsCanvas->clear(); 00306 if (mSlider.isSet()) mSlider->value(0); 00307 mAltOffset = 0.0f; 00308 } 00309 00310 /**************************************************************************/ 00311 void cGuiButtonSelectBox::selected( const cDynVar &iValue ) 00312 { 00313 for (tUint i=0; i!=mValues.size(); ++i) 00314 if (mValues[i]==iValue) { 00315 selectedByIndex(i); 00316 return; 00317 } 00318 } 00319 00320 /**************************************************************************/ 00321 void cGuiButtonSelectBox::selectedByLabel( const cDynVar &iValue ) 00322 { 00323 for (tUint i=0; i!=mButtons.size(); ++i) 00324 if (mButtons[i]->label()==iValue) { 00325 selectedByIndex(i); 00326 return; 00327 } 00328 } 00329 00330 /**************************************************************************/ 00331 const cDynVar &cGuiButtonSelectBox::getValueByLabel( const cDynVar &iValue ) 00332 { 00333 for (tUint i=0; i!=mButtons.size(); ++i) 00334 if (mButtons[i]->label()==iValue) 00335 return mValues[i]; 00336 return cDynVar::Null; 00337 } 00338 00339 /**************************************************************************/ 00340 void cGuiButtonSelectBox::selectedByIndex( const tUint &iIndex ) 00341 { 00342 if (iIndex>=mButtons.size()) 00343 throw cOutOfBoundsException( 00344 "cGuiButtonSelectBox::selectedByIndex", 00345 "Selected index does not exist in this list" ); 00346 00347 if (multiple()) { 00348 if (mButtons[iIndex]->toggledOn()) 00349 broadcastSelected(iIndex); 00350 else 00351 broadcastUnselected(iIndex); 00352 00353 } else { 00354 if (iIndex==mSelected && noUnselect()) { 00355 mButtons[mSelected]->toggledOn(true); 00356 return; 00357 } 00358 00359 if (mSelected != NoSelection) { 00360 mButtons[mSelected]->toggledOn(false); 00361 broadcastUnselected(mSelected); 00362 } 00363 00364 if (iIndex!=mSelected) { 00365 mButtons[iIndex]->toggledOn(true); 00366 mSelected = iIndex; 00367 broadcastSelected(iIndex); 00368 } else 00369 mSelected = NoSelection; 00370 } 00371 00372 // Do stuff. 00373 } 00374 00375 /**************************************************************************/ 00376 void cGuiButtonSelectBox::selectNext() 00377 { 00378 if (mButtons.empty()) return; 00379 tUint s = mSelected; 00380 if (s==NoSelection) { 00381 selected( mValues[0] ); 00382 return; 00383 } 00384 ++s; 00385 if (s==mButtons.size()) 00386 selected( mValues[0] ); 00387 else 00388 selected( mValues[s] ); 00389 } 00390 00391 /**************************************************************************/ 00392 void cGuiButtonSelectBox::selectPrev() 00393 { 00394 if (mButtons.empty()) return; 00395 tSint s = mSelected; 00396 if (tUint(s)==NoSelection) { 00397 selected( mValues[mButtons.size()-1] ); 00398 return; 00399 } 00400 --s; 00401 if (s==-1) 00402 selected( mValues[mButtons.size()-1] ); 00403 else 00404 selected( mValues[s] ); 00405 } 00406 00407 /**************************************************************************/ 00408 const cAutoPtr<cGuiButton> &cGuiButtonSelectBox::getButton( 00409 const cDynVar &iValue ) 00410 { 00411 static const cAutoPtr<cGuiButton> NoValue = 0; 00412 for (tUint i=0; i!=mValues.size(); ++i) 00413 if (mValues[i]==iValue) { 00414 return getButtonByIndex(i); 00415 } 00416 return NoValue; 00417 } 00418 00419 /**************************************************************************/ 00420 const cAutoPtr<cGuiButton> &cGuiButtonSelectBox::getButtonByLabel( 00421 const cDynVar &iLabel ) 00422 { 00423 static const cAutoPtr<cGuiButton> NoValue = 0; 00424 for (tUint i=0; i!=mButtons.size(); ++i) 00425 if (mButtons[i]->label()==iLabel) { 00426 return getButtonByIndex(i); 00427 } 00428 return NoValue; 00429 } 00430 00431 /**************************************************************************/ 00432 const cAutoPtr<cGuiButton> &cGuiButtonSelectBox::getButtonByIndex( 00433 const tUint &iIndex ) 00434 { 00435 if (iIndex>=mButtons.size()) 00436 throw cOutOfBoundsException( 00437 "cGuiButtonSelectBox::getButtonByIndex", 00438 "Selected index does not exist in this list" ); 00439 00440 return mButtons[iIndex]; 00441 } 00442 00443 /**************************************************************************/ 00444 const cDynVar &cGuiButtonSelectBox::selected() const 00445 { 00446 if (multiple()) { 00447 mTmpValueList = cDynVar::Array; 00448 for (tUint i=0; i!=mButtons.size(); ++i) 00449 if (mButtons[i]->toggledOn()) 00450 mTmpValueList.insert( mValues[i] ); 00451 return mTmpValueList; 00452 } 00453 if (mSelected==NoSelection) 00454 return cDynVar::Null; 00455 return mValues[mSelected]; 00456 } 00457 00458 /**************************************************************************/ 00459 const tBool cGuiButtonSelectBox::wantsFocus() const 00460 { 00461 return true; 00462 } 00463 00464 /**************************************************************************/ 00465 const cAutoPtr<cGuiElement> cGuiButtonSelectBox::clone() const 00466 { 00467 cAutoPtr<cGuiElement> newElement( new cGuiButtonSelectBox ); 00468 cloneInto( newElement ); 00469 return newElement; 00470 } 00471 00472 /**************************************************************************/ 00473 void cGuiButtonSelectBox::cloneInto( 00474 const cAutoPtr<cGuiButtonSelectBox> &i_ioElement ) const 00475 { 00476 // Parent Properties first 00477 cGuiInteractive::cloneInto( i_ioElement ); 00478 00479 // Now our properties. 00480 if (mSlider) i_ioElement->slider( *mSlider ); 00481 i_ioElement->multiple( mMultiple ); 00482 00483 // Add our children 00484 const tUint NumButtons( mValues.size() ); 00485 for (tUint i=0; i<NumButtons; ++i) 00486 i_ioElement->addButton( mValues[i], mButtons[i]->label(), 00487 *(mButtons[i]) ); 00488 00489 if (mSelected!=NoSelection) 00490 i_ioElement->selected( mValues[mSelected] ); 00491 00492 i_ioElement->noUnselect( noUnselect() ); 00493 00494 i_ioElement->mAltOffset = mAltOffset; 00495 } 00496 00497 /**************************************************************************/ 00498 void cGuiButtonSelectBox::dimensionChanged() 00499 { 00500 // Make sure our parents have a chance to react to this 00501 cGuiInteractive::dimensionChanged(); 00502 00503 // Remap our children to fit in our new dimensions 00504 tFloat sliderSpace( 0.0f ); 00505 if (mSlider.isSet()) { 00506 sliderSpace = mSlider->size().x(); 00507 mSlider->pos( tGuiPos(innerPos().x()+innerSize().x()-sliderSpace, 00508 innerPos().y()) ); 00509 mSlider->size( tGuiPos(sliderSpace, innerSize().y()) ); 00510 mSlider->range(size().y()); 00511 mSlider->max(size().y()); 00512 } 00513 00514 mButtonsCanvas->pos( innerPos() ); 00515 mButtonsCanvas->size( tGuiPos(innerSize().x()-sliderSpace, 00516 innerSize().y()) ); 00517 00518 // We could and should have an option to keep button sizes 00519 // fixed, or automatically scale them to the size allocated. 00520 // When that option is added, we'd go through our buttons here 00521 // and set the size to match the buttons canvas size. 00522 } 00523 00524 /**************************************************************************/ 00525 void cGuiButtonSelectBox::processKey( const tKey &iKey, 00526 const tKeyMods &iMods ) 00527 { 00528 switch (iKey) { 00529 case Key_Down: 00530 case Key_KP2: 00531 selectNext(); 00532 break; 00533 case Key_Up: 00534 case Key_KP8: 00535 selectPrev(); 00536 break; 00537 default: 00538 break; 00539 } 00540 } 00541 00542 /**************************************************************************/ 00543 void cGuiButtonSelectBox::keystrokeCallback( cGuiElement *const i_ioElement, 00544 const tGuiActionType iType, const tActionData &iData ) 00545 { 00546 if (!tBool(iData["pressed"])) return; 00547 dynamic_cast<cGuiButtonSelectBox*>(i_ioElement)->processKey( 00548 tKey(tSint(iData["key"])), tKeyMods(tSint(iData["mods"])) ); 00549 } 00550 00551 /**************************************************************************/ 00552 void cGuiButtonSelectBox::broadcastUnselected( const tUint &iIndex ) 00553 { 00554 cDynVar actionData( cDynVar::Array ); 00555 actionData["name"] = name(); 00556 actionData["value"] = mValues[iIndex]; 00557 actionData["index"] = tSint(iIndex); 00558 broadcastAction( GuiActionType_Unselected, actionData ); 00559 } 00560 00561 /**************************************************************************/ 00562 void cGuiButtonSelectBox::broadcastSelected( const tUint &iIndex ) 00563 { 00564 cDynVar actionData( cDynVar::Array ); 00565 actionData["name"] = name(); 00566 actionData["selectedValue"] = mValues[iIndex]; // Compat 00567 actionData["value"] = mValues[iIndex]; 00568 actionData["index"] = tSint(iIndex); 00569 broadcastAction( GuiActionType_Selected, actionData ); 00570 } 00571 00572 /**************************************************************************/ 00573 void cGuiButtonSelectBox::reset() 00574 { 00575 // Set up an empty canvas 00576 mButtonsCanvas = new cGuiCanvas; 00577 mButtonsCanvas->clipping( true ); 00578 00579 // We have no slider 00580 mSlider = 0; 00581 mAltOffset = 0.0f; 00582 00583 // Make this a single select box 00584 mMultiple = false; 00585 mNoUnselect = false; 00586 mSelected = NoSelection; 00587 00588 // Start the button placement over. 00589 mNextButtonPos.set(0.0f,0.0f); 00590 00591 bindAction( GuiActionType_Keystroke, 00592 new cGuiSimpleCallbackAction<cGuiButtonSelectBox::keystrokeCallback>, 00593 false ); 00594 } 00595 00596 /**************************************************************************/ 00597 cGuiButtonSelectBox::cItemSelectedAction::cItemSelectedAction( 00598 cGuiButtonSelectBox *const iParent, const cDynVar &iValue ) : 00599 mParent( iParent ), 00600 mValue( iValue ) 00601 { 00602 } 00603 00604 /**************************************************************************/ 00605 cGuiButtonSelectBox::cItemSelectedAction::~cItemSelectedAction() 00606 { 00607 } 00608 00609 /**************************************************************************/ 00610 void cGuiButtonSelectBox::cItemSelectedAction::execute( 00611 cGuiElement *const i_ioElement, const tGuiActionType iType, 00612 const tActionData &iData ) 00613 { 00614 mParent->selected( mValue ); 00615 } 00616 00617 /**************************************************************************/ 00618 const cAutoPtr<cGuiACInt> 00619 cGuiButtonSelectBox::cItemSelectedAction::clone() const 00620 { 00621 throw cUnsupportedMethodException( 00622 "cGuiButtonSelectBox::cItemSelectedAction::clone", 00623 "This class may not be cloned." ); 00624 /* cAutoPtr<cGuiButtonSelectBox::cItemSelectedAction> action = 00625 new cGuiButtonSelectBox::cItemSelectedAction(); 00626 00627 cloneInto( action ); 00628 return action; 00629 */ 00630 } 00631 00632 /**************************************************************************/ 00633 void cGuiButtonSelectBox::cItemSelectedAction::cloneInto( 00634 const cAutoPtr<cItemSelectedAction> &ioElement ) const 00635 { 00636 throw cUnsupportedMethodException( 00637 "cGuiButtonSelectBox::cItemSelectedAction::cloneInto", 00638 "This class may not be cloned." ); 00639 } 00640 00641 } // namespace n2l |