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:36pm
Front Page Journal Projects Your Profile About
[]

LibN2L-4 Library Code Reference

Classes
Compounds
Files
Members
Method Index
Full Reference

cGuiButtonSelectBox.cpp

Go 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
©2012 Aaron Cameron