AaronCameron.net
Because you all make me very, very tired.
Not a Member? - Login or Create an Account
Sunday the 5th of February 2012 @ 05:05pm
Front Page Journal Projects Your Profile About
[]

LibN2L-4 Library Code Reference

Classes
Compounds
Files
Members
Method Index
Full Reference

cGuiTextInput.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/cGuiTextInput.h"
00026 
00027 #include "n2l/vfs.h"
00028 #include "n2l/dynVars.h"
00029 
00030 #include "n2l/materials.h"
00031 #include "n2l/fonts.h"
00032 
00033 #include "n2l/resourceManagement.h"
00034 
00035 #include "gui/cGuiCanvas.h"
00036 
00037 #include "gui/cGuiSimpleCallbackAction.h"
00038 
00039 #include "gui/guiUtilities.h"
00040 
00041 #include "gui/cGuiFactory.h"
00042 
00043 namespace n2l
00044 {
00045 #   ifdef N2L_PASSIVE_GUI_REG
00046         tBool cGuiTextInput::smRegistered =
00047             cGuiFactory::current().registerLoader( "n2l::cGuiTextInput",
00048             cGuiElement::loadNew<cGuiTextInput> );
00049 #   endif
00050 
00051     /**************************************************************************/
00052     cGuiTextInput::cGuiTextInput()
00053     {
00054         init();
00055     }
00056 
00057     /**************************************************************************/
00058     cGuiTextInput::cGuiTextInput( const cVfsNodeInterface &iNode )
00059     {
00060         init();
00061         load( iNode );
00062     }
00063 
00064     /**************************************************************************/
00065     cGuiTextInput::cGuiTextInput( const cDynVar &iDef )
00066     {
00067         init();
00068         load( iDef );
00069     }
00070 
00071 
00072     /**************************************************************************/
00073     cGuiTextInput::~cGuiTextInput()
00074     {
00075     }
00076 
00077     /**************************************************************************/
00078     void cGuiTextInput::load( const cVfsNodeInterface &iNode )
00079     {
00080         const tUint DataOffset =
00081             vfsNodeFileWithHeader( iNode, "onyx::cGuiTextInput");
00082         cDynVar def;
00083         def.unserialize( iNode.buffer().c_str()+DataOffset );
00084         load( def );
00085     }
00086 
00087     /**************************************************************************/
00088     void cGuiTextInput::load( const cDynVar &iDef )
00089     {
00090         cGuiInteractive::load( iDef );
00091 
00092         // Step through the fills and styles
00093         if (iDef.keyExistsAsArray("textStyle"))
00094             for (cDynVar::tConstIterator i=iDef["textStyle"].begin();
00095                 i!=iDef["textStyle"].end(); ++i)
00096             {
00097                 textStyle( tState(asSint(i->first)),
00098                     *n2lgui_loadOrBuild<cGuiTextStyle>(i->second) );
00099             }
00100 
00101         if (iDef.keyExistsAsArray("background"))
00102             for (cDynVar::tConstIterator i=iDef["background"].begin();
00103                 i!=iDef["background"].end(); ++i)
00104             {
00105                 fill( tState(asSint(i->first)), Prop_Background,
00106                     *n2lgui_loadOrBuild<cGuiFill>(i->second) );
00107             }
00108 
00109         if (iDef.keyExistsAsArray("cursor"))
00110             for (cDynVar::tConstIterator i=iDef["cursor"].begin();
00111                 i!=iDef["cursor"].end(); ++i)
00112             {
00113                 fill( tState(asSint(i->first)), Prop_Cursor,
00114                     *n2lgui_loadOrBuild<cGuiFill>(i->second) );
00115             }
00116 
00117         // Leave the rest as default, because I'm just that lazy.
00118 
00119     }
00120 
00121     /**************************************************************************/
00122     void cGuiTextInput::fill( const tState &iState, const tProp &iProp,
00123         const cGuiFill &iFill )
00124     {
00125         boundCheckState(iState,"cGuiTextInput::fill");
00126         boundCheckProp(iProp,"cGuiTextInput::fill");
00127         mFill[iState][iProp] = iFill;
00128     }
00129 
00130     /**************************************************************************/
00131     void cGuiTextInput::textStyle( const tState &iState, 
00132         const cGuiTextStyle &iStyle )
00133     {
00134         boundCheckState(iState,"cGuiTextInput::textStyle");
00135         mTextStyle[iState] = iStyle;
00136     }
00137 
00138     /**************************************************************************/
00139     void cGuiTextInput::draw() const
00140     {
00141         const tState curState =
00142             (cGuiElement::focus()?State_Focused:State_Normal);
00143         mFill[curState][Prop_Background].draw( outerPos(), outerSize() );
00144         mTextStyle[curState].draw( innerPos(), innerSize(), mValue,
00145             mFirstCharIndex, (mEndCharIndex-mFirstCharIndex) );
00146     }
00147 
00148     /**************************************************************************/
00149     void cGuiTextInput::valValFunc( const tValValFunc &iFunc )
00150     {
00151         mValValFunc = iFunc;
00152     }
00153 
00154     /**************************************************************************/
00155     void cGuiTextInput::value( const tValue & iValue )
00156     {
00157         mValue = iValue;
00158         mFirstCharIndex = 0;
00159         mEndCharIndex = 0;
00160         mCursor = 0;
00161         calculatePropPositions();
00162     }
00163 
00164     /**************************************************************************/
00165     const cGuiTextInput::tValue & cGuiTextInput::value() const
00166     {
00167         return mValue;
00168     }
00169     
00170     /**************************************************************************/
00171     void cGuiTextInput::init()
00172     {
00173         mValue = "";
00174         mCursor = 0;
00175         mFirstCharIndex = 0;
00176         mEndCharIndex = 0;
00177 
00178         mValValFunc = 0;
00179 
00180         mFill[State_Normal][Prop_Background].colour(
00181             cColour(0.25f,0.25f,0.25f,1.0f) );
00182         mFill[State_Focused][Prop_Background].colour(
00183             cColour(0.33f,0.33f,0.33f,1.0f) );
00184 
00185         calculatePropPositions();
00186 
00187         bindAction( GuiActionType_Clicked,
00188             new cGuiSimpleCallbackAction<cGuiTextInput::clickedCallback>,
00189             false );
00190 
00191         bindAction( GuiActionType_FocusChanged,
00192             new cGuiSimpleCallbackAction<cGuiTextInput::focusChangeCallback>,
00193             false );
00194 
00195         bindAction( GuiActionType_Keystroke,
00196             new cGuiSimpleCallbackAction<cGuiTextInput::keystrokeCallback>,
00197             false );
00198     }
00199 
00200     /**************************************************************************/
00201     void cGuiTextInput::processKey( const tKey &iKey, const tKeyMods &iMods )
00202     {
00203         tValue oldVal = mValue;
00204         tUint oldCursor = mCursor;
00205 
00206         // Do controls first.
00207         if (iKey==Key_Backspace && mCursor!=0) {
00208             --mCursor;
00209             if (!mValue.empty()) mValue.erase(mCursor);
00210 
00211             if (iMods & KMod_Ctrl) {
00212                 while (!mValue.empty() && mValue[mCursor-1]!=' ')
00213                     mValue.erase(--mCursor);
00214             }
00215 
00216         } else if ((iKey>=Key_A && iKey<=Key_Z) ||
00217             (iKey>=Key_1 && iKey<=Key_0) ||
00218             iKey==' ' || iKey=='.' ||
00219             iKey==',')
00220         {
00221             if (iMods&KMod_InCaps)
00222                 mValue += iKey-32;
00223             else mValue += iKey;
00224             ++mCursor;
00225 
00226         } else return;
00227 
00228         tActionData data( tActionData::Array );
00229 
00230         if (mValValFunc && !mValValFunc( mValue )) {
00231             mValue = oldVal;
00232             mCursor = oldCursor;
00233             data.insert( "failedValidation", true );
00234         }
00235 
00236         calculatePropPositions();
00237 
00238         
00239         data.insert("name", name() );
00240         data.insert("value", mValue );
00241         broadcastAction( GuiActionType_ValueChanged, data );
00242     }
00243 
00244     /**************************************************************************/
00245     void cGuiTextInput::dimensionChanged()
00246     {
00247         cGuiInteractive::dimensionChanged();
00248         calculatePropPositions();
00249     }
00250 
00251     /**************************************************************************/
00252     void cGuiTextInput::cloneInto(
00253         const cAutoPtr<cGuiTextInput> &ioElement ) const
00254     {
00255         // Parent Properties first
00256         cGuiInteractive::cloneInto( ioElement );
00257 
00258         ioElement->mValue = mValue;
00259         ioElement->mCursor = mCursor;
00260 
00261         ioElement->mFirstCharIndex = mFirstCharIndex;
00262         ioElement->mEndCharIndex = mEndCharIndex;
00263 
00264         for (tUint s=State_Normal; s!=State_NumStates; ++s) {
00265             for (tUint p=Prop_Background; p!=Prop_NumProps; ++p)
00266                 ioElement->mFill[s][p] = mFill[s][p];
00267             ioElement->mTextStyle[s] = mTextStyle[s];
00268             
00269         }
00270 
00271         ioElement->calculatePropPositions();
00272     }
00273 
00274     /**************************************************************************/
00275     void cGuiTextInput::calculatePropPositions()
00276     {
00277         const tState CurState =
00278             (cGuiElement::focus()?State_Focused:State_Normal);
00279 
00280         if (!mTextStyle[CurState].font().isSet()) return;
00281         const cAutoPtr<const cFontInterface> Font(mTextStyle[CurState].font());
00282         
00283         if (mValue.size()) {
00284             const tFloat GlyphSeperation =
00285                 Font->glyphSeperation(innerSize().y());
00286 
00287             tFloat strSize = 0;
00288             // We have to move the displayed characters one way or 
00289             // another depending on the cursor position.  Do that now.
00290             if (mCursor>mEndCharIndex) {
00291                 // Recalculate to fit the new character, back to front.
00292                 mEndCharIndex = mCursor;
00293                 mFirstCharIndex = mEndCharIndex;
00294                 while (strSize<innerSize().x() && mFirstCharIndex!=0) {
00295                     strSize += Font->glyphWidth(    mValue[mFirstCharIndex-1],
00296                                                     innerSize().y() );
00297                     strSize += GlyphSeperation;
00298                     if (strSize>=innerSize().x()) continue;
00299                     --mFirstCharIndex;
00300                 }
00301             } else if (mCursor<=mFirstCharIndex) {
00302                 // Recalculate to fit 50% back on the screen, front to back.
00303                 if (mEndCharIndex-mFirstCharIndex>mFirstCharIndex)
00304                     mFirstCharIndex = 0;
00305                 else mFirstCharIndex -= mEndCharIndex-mFirstCharIndex;
00306                 mEndCharIndex = mFirstCharIndex;
00307                 while (strSize<innerSize().x() &&
00308                     mEndCharIndex!=mValue.size())
00309                 {
00310                     strSize += Font->glyphWidth(    mValue[mEndCharIndex],
00311                                                     innerSize().y() );
00312                     strSize += GlyphSeperation;
00313                     if (strSize>=innerSize().x()) continue;
00314                     ++mEndCharIndex;
00315                 }
00316             }
00317         } // mvalue size
00318         
00319     }
00320 
00321     /**************************************************************************/
00322     const tBool cGuiTextInput::wantsFocus() const
00323     {
00324         return true;
00325     }
00326 
00327     /**************************************************************************/
00328     const cAutoPtr<cGuiElement> cGuiTextInput::clone() const
00329     {
00330         cAutoPtr<cGuiElement> newElement( new cGuiTextInput );
00331         cloneInto( newElement );
00332         return newElement;
00333     }
00334 
00335     /**************************************************************************/
00336     void cGuiTextInput::focusChangeCallback( cGuiElement *const i_ioElement,
00337         const tGuiActionType iType, const tActionData & iData )
00338     {
00339     }
00340 
00341     /**************************************************************************/
00342     void cGuiTextInput::clickedCallback( cGuiElement *const i_ioElement,
00343         const tGuiActionType iType, const tActionData & iData )
00344     {
00345         i_ioElement->focus(true);
00346     }
00347 
00348     /**************************************************************************/
00349     void cGuiTextInput::keystrokeCallback( cGuiElement *const i_ioElement,
00350         const tGuiActionType iType, const tActionData & iData )
00351     {
00352         if (!tBool(iData["pressed"])) return;
00353         dynamic_cast<cGuiTextInput*>(i_ioElement)->processKey(
00354             tKey(tSint(iData["key"])), tKeyMods(tSint(iData["mods"])) );
00355     }
00356 
00357     /**************************************************************************/
00358     void cGuiTextInput::boundCheckState( const tState &iState,
00359         const tString &iFrom )
00360     {
00361         if (iState<State_Normal || iState>=State_NumStates)
00362             throw cOutOfBoundsException( iFrom, "State out of bounds");
00363     }
00364 
00365     /**************************************************************************/
00366     void cGuiTextInput::boundCheckProp( const tProp &iProp,
00367         const tString &iFrom )
00368     {
00369         if (iProp<Prop_Background || iProp>=Prop_NumProps)
00370             throw cOutOfBoundsException( iFrom, "Property out of bounds");
00371     }
00372 
00373 } // namespace n2l
©2012 Aaron Cameron