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