123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2013 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "console/consoleTypes.h"
- #include "console/console.h"
- #include "graphics/gColor.h"
- #include "graphics/dgl.h"
- #include "gui/guiCanvas.h"
- #include "gui/guiTextEditCtrl.h"
- #include "gui/guiDefaultControlRender.h"
- #include "memory/frameAllocator.h"
- #include "string/unicode.h"
- #include <vector>
- #include <string>
- #include "guiTextEditCtrl_ScriptBinding.h"
- #pragma region GuiTextEditTextBlock
- GuiTextEditTextBlock::GuiTextEditTextBlock()
- {
- mGlobalBounds.set(0, 0, 0, 0);
- mTextOffsetX = 0;
- mTextScrollX = 0;
- mText = string();
- mLineStartIbeamValue = 0;
- }
- void GuiTextEditTextBlock::render(const RectI& bounds, string line, U32 ibeamStartValue, GuiControlProfile* profile, GuiControlState currentState, GuiTextEditSelection& selector, AlignmentType align, GFont* font, bool overrideFontColor)
- {
- mGlobalBounds.set(bounds.point, bounds.extent);
- mText.assign(line);
- mLineStartIbeamValue = ibeamStartValue;
- RectI clipRect = dglGetClipRect();
- if (mGlobalBounds.overlaps(clipRect))
- {
- const U32 selStart = selector.getSelStart();
- const U32 selEnd = selector.getSelEnd();
- U32 lengthOfPreBlockText = mClamp(selStart - mLineStartIbeamValue, 0, line.length());
- U32 lengthOfPostBlockText = mClamp(line.length() - (selEnd - mLineStartIbeamValue), 0, line.length());
- U32 lengthOfHighlightBlockText = mClamp(line.length() - (lengthOfPreBlockText + lengthOfPostBlockText), 0, line.length());
- processTextAlignment(line, font, align);
- Point2I movingStartPoint = getGlobalTextStart();
- movingStartPoint.x += renderTextSection(movingStartPoint, 0, lengthOfPreBlockText, profile, currentState, font, false, overrideFontColor);
- movingStartPoint.x += renderTextSection(movingStartPoint, lengthOfPreBlockText, lengthOfHighlightBlockText, profile, currentState, font, true, overrideFontColor);
- movingStartPoint.x += renderTextSection(movingStartPoint, lengthOfPreBlockText + lengthOfHighlightBlockText, lengthOfPostBlockText, profile, currentState, font, false, overrideFontColor);
- }
- Point2I textStartPoint = getGlobalTextStart();
- if (selector.renderIbeam(textStartPoint, mGlobalBounds.extent, line, mLineStartIbeamValue, mLineStartIbeamValue + line.length(), profile, font))
- {
- Point2I cursorCenter = selector.getCursorCenter();
- performScrollJumpX(cursorCenter.x, clipRect.point.x, clipRect.point.x + clipRect.extent.x);
- }
- }
- U32 GuiTextEditTextBlock::renderTextSection(const Point2I& startPoint, const U32 subStrStart, const U32 subStrLen, GuiControlProfile* profile, const GuiControlState currentState, GFont* font, bool isSelectedText, bool overrideFontColor)
- {
- if (subStrLen != 0)
- {
- string sectionText = mText.substr(subStrStart, subStrLen);
- U32 blockStrWidth = font->getStrWidth(sectionText.c_str());
- Point2I pointToDraw = Point2I(startPoint.x, startPoint.y);
- if (isSelectedText)
- {
- if (!overrideFontColor)
- {
- dglSetBitmapModulation(profile->mFontColorTextSL);
- }
- RectI highlightRect = RectI(pointToDraw.x, pointToDraw.y, blockStrWidth, mGlobalBounds.extent.y);
- dglDrawRectFill(highlightRect, profile->mFillColorTextSL);
- }
- else if(!overrideFontColor)
- {
- const ColorI& fontColor = profile->getFontColor(currentState);
- dglSetBitmapModulation(fontColor);
- }
- dglDrawText(font, pointToDraw, sectionText.c_str(), profile->mFontColors);
- return blockStrWidth;
- }
- return 0;
- }
- void GuiTextEditTextBlock::performScrollJumpX(const S32 targetX, const S32 areaStart, const S32 areaEnd)
- {
- S32 diff = 0;
- if (targetX < areaStart)
- {
- diff = targetX - areaStart;
- }
- else if (targetX > areaEnd)
- {
- diff = targetX - areaEnd;
- }
- mTextScrollX += diff;
- }
- U32 GuiTextEditTextBlock::calculateIbeamPositionInLine(const S32 targetX, GFont* font)
- {
- if (mText.length() == 0)
- return mLineStartIbeamValue;
- S32 curX = getGlobalTextStart().x;
- U32 result = mText.length();
- for (U32 count = 0; count < mText.length(); count++)
- {
- char c = mText[count];
- if (!font->isValidChar(c))
- continue;
- S32 backDiff = mAbs(curX - targetX);
- curX += font->getCharXIncrement(c);
- if (curX > targetX)
- {
- S32 forwardDiff = mAbs(curX - targetX);
- if (backDiff < forwardDiff)
- result = count;
- else
- result = count + 1;
- break;
- }
- }
- return result;
- }
- void GuiTextEditTextBlock::processScrollVelocity(const S32 delta, const S32 extentX, GFont* font)
- {
- U32 max = font->getStrWidth(mText.c_str()) - extentX;
- mTextScrollX = mClamp(mTextScrollX + delta, 0, max);
- }
- void GuiTextEditTextBlock::processTextAlignment(const string line, GFont* font, AlignmentType align)
- {
- if (align == AlignmentType::LeftAlign ||
- mGlobalBounds.extent.x < font->getStrWidth(line.c_str()))
- {
- mTextOffsetX = 0;
- }
- else if (align == AlignmentType::RightAlign)
- {
- mTextOffsetX = mGlobalBounds.extent.x - font->getStrWidth(line.c_str());
- }
- else if (align == AlignmentType::CenterAlign)
- {
- mTextOffsetX = (S32)mRound((mGlobalBounds.extent.x - font->getStrWidth(line.c_str())) / 2);
- }
- }
- #pragma endregion
- #pragma region GuiTextEditSelection
- GuiTextEditSelection::GuiTextEditSelection()
- {
- mBlockStart = 0;
- mBlockEnd = 0;
- mCursorPos = 0;
- mCursorOn = false;
- mNumFramesElapsed = 0;
- mCursorAtEOL = false;
- mIsFirstResponder = false;
- mGlobalUnadjustedCursorRect.set(0, 0, 0, 0);
- mCursorRendered = false;
- mNumFramesElapsed = 0;
- mTimeLastCursorFlipped = 0;
- mCursorOn = false;
- }
- bool GuiTextEditSelection::renderIbeam(const Point2I& startPoint, const Point2I& extent, const string line, const U32 start, const U32 end, GuiControlProfile* profile, GFont* font)
- {
- if (!mIsFirstResponder || !mCursorOn ||
- (mCursorAtEOL && mCursorPos == start && mCursorPos != 0) ||
- (!mCursorAtEOL && mCursorPos == end && mCursorPos != mTextLength) ||
- (mCursorPos < start || mCursorPos > end))
- {
- return false;
- }
- string blockText = line.substr(0, mCursorPos - start);
- U32 blockStrWidth = font->getStrWidth(blockText.c_str());
- RectI ibeamRect = RectI(startPoint.x + blockStrWidth - 1, startPoint.y, 2, extent.y);
- setCursorRect(ibeamRect);
- RectI clipRect = dglGetClipRect();
- if (clipRect.point.x > ibeamRect.point.x)
- {
- ibeamRect.point.x = clipRect.point.x;
- }
- else if ((clipRect.point.x + clipRect.extent.x) < (ibeamRect.point.x + ibeamRect.extent.x))
- {
- ibeamRect.point.x = (clipRect.point.x + clipRect.extent.x) - ibeamRect.extent.x;
- }
- dglDrawRectFill(ibeamRect, profile->mCursorColor);
- return true;
- }
- void GuiTextEditSelection::selectTo(const U32 target)
- {
- S32 safeTarget = mClamp(target, 0, mTextLength);
- if (mBlockStart == mBlockEnd)
- {
- mBlockAnchor = mBlockStart = mBlockEnd = mCursorPos;
- }
- if (safeTarget > mBlockAnchor)
- {
- mBlockStart = mBlockAnchor;
- mBlockEnd = mCursorPos = safeTarget;
- }
- else if (safeTarget < mBlockAnchor)
- {
- mBlockStart = mCursorPos = safeTarget;
- mBlockEnd = mBlockAnchor;
- }
- else
- {
- mCursorPos = mBlockStart = mBlockEnd = safeTarget;
- }
- }
- void GuiTextEditSelection::eraseSelection(string& fullText)
- {
- if (hasSelection())
- {
- fullText.erase(mBlockStart, mBlockEnd - mBlockStart);
- mCursorPos = mBlockStart;
- mTextLength = fullText.length();
- clearSelection();
- }
- }
- void GuiTextEditSelection::onPreRender(const U32 time)
- {
- if (mIsFirstResponder)
- {
- U32 timeElapsed = time - mTimeLastCursorFlipped;
- mNumFramesElapsed++;
- if ((timeElapsed > 400) && (mNumFramesElapsed > 3))
- {
- mCursorOn = !mCursorOn;
- mTimeLastCursorFlipped = time;
- mNumFramesElapsed = 0;
- }
- }
- }
- void GuiTextEditSelection::resetCursorBlink()
- {
- mCursorOn = true;
- mNumFramesElapsed = 0;
- mTimeLastCursorFlipped = Platform::getVirtualMilliseconds();
- }
- void GuiTextEditSelection::selectWholeWord(const string& text)
- {
- bool selectingSpace = (mCursorPos < text.length() && text[mCursorPos] == ' ');
- for (S32 i = mCursorPos; i >= 0; i--)
- {
- if (i == 0)
- {
- mBlockStart = 0;
- break;
- }
- if ((!selectingSpace && text[i - 1] == ' ') ||
- (selectingSpace && text[i - 1] != ' '))
- {
- mBlockStart = i;
- break;
- }
- }
- mBlockAnchor = mBlockStart;
- bool foundSpace = false;
- for (S32 j = mCursorPos; j <= (text.length() + 1); j++)
- {
- if (j == (text.length() + 1))
- {
- mBlockEnd = j;
- break;
- }
- if (!foundSpace && text[j] == ' ')
- {
- foundSpace = true;
- }
- else if (foundSpace && text[j] != ' ')
- {
- mBlockEnd = j;
- break;
- }
- }
- mCursorPos = mBlockEnd;
- mCursorAtEOL = true;
- }
- GuiTextEditSelection::GuiTextEditSelection(const GuiTextEditSelection& selector)
- {
- mBlockAnchor = selector.mBlockAnchor;
- mBlockStart = selector.mBlockStart;
- mBlockEnd = selector.mBlockEnd;
- mCursorPos = selector.mCursorPos;
- mCursorAtEOL = selector.mCursorAtEOL;
- mIsFirstResponder = selector.mIsFirstResponder;
- mGlobalUnadjustedCursorRect = selector.mGlobalUnadjustedCursorRect;
- mCursorRendered = selector.mCursorRendered;
- mTextLength = selector.mTextLength;
- mNumFramesElapsed = 0;
- mTimeLastCursorFlipped = Platform::getVirtualMilliseconds();
- mCursorOn = true;
- }
- void GuiTextEditSelection::stepCursorForward()
- {
- if (hasSelection())
- {
- setCursorPosition(mBlockEnd);
- }
- else
- {
- setCursorPosition(mCursorPos + 1);
- }
- }
- void GuiTextEditSelection::stepCursorBackward()
- {
- if (hasSelection())
- {
- setCursorPosition(mBlockStart);
- }
- else
- {
- setCursorPosition(mCursorPos - 1);
- }
- }
- #pragma endregion
- #pragma region GuiTextEditCtrl
- IMPLEMENT_CONOBJECT(GuiTextEditCtrl);
- U32 GuiTextEditCtrl::smNumAwake = 0;
- GuiTextEditCtrl::GuiTextEditCtrl()
- {
- mInsertOn = true;
- mMouseOver = false;
- mPasswordText = false;
- mReturnCausesTab = false;
- mSinkAllKeyEvents = false;
- mActive = true;
- mSelector = GuiTextEditSelection();
- mUndoSelector = GuiTextEditSelection();
- mUndoText = string();
- mTextOffsetY = 0;
- mReturnCommand = StringTable->EmptyString;
- mEscapeCommand = StringTable->EmptyString;
- mPasswordMask = StringTable->insert( "*" );
- mEditCursor = NULL;
- mMaxStrLen = MAX_STRING_LENGTH;
- mInputMode = AllText;
- mSuspendVerticalScrollJump = false;
- mTextBlockList = TextBlockList();
- mScrollVelocity = 0;
- }
- static EnumTable::Enums inputModeEnums[] =
- {
- { GuiTextEditCtrl::AllText, "AllText" },
- { GuiTextEditCtrl::Decimal, "Decimal" },
- { GuiTextEditCtrl::Number, "Number" },
- { GuiTextEditCtrl::Alpha, "Alpha" },
- { GuiTextEditCtrl::AlphaNumeric, "AlphaNumeric" }
- };
- static EnumTable gInputModeTable(5, &inputModeEnums[0]);
- void GuiTextEditCtrl::initPersistFields()
- {
- Parent::initPersistFields();
- addDepricatedField("validate");
- addDepricatedField("truncate");
- addDepricatedField("passwordMask");
- addDepricatedField("historySize");
- addDepricatedField("tabComplete");
- addGroup("Text Edit");
- addField("returnCommand", TypeString, Offset(mReturnCommand, GuiTextEditCtrl));
- addField("escapeCommand", TypeString, Offset(mEscapeCommand, GuiTextEditCtrl));
- addField("sinkAllKeyEvents", TypeBool, Offset(mSinkAllKeyEvents, GuiTextEditCtrl));
- addField("password", TypeBool, Offset(mPasswordText, GuiTextEditCtrl));
- addField("returnCausesTab", TypeBool, Offset(mReturnCausesTab, GuiTextEditCtrl));
- addProtectedField("maxLength", TypeS32, Offset(mMaxStrLen, GuiTextEditCtrl), &setMaxLengthProperty, &defaultProtectedGetFn, "The max number of characters that can be entered into the text edit box.");
- addProtectedField("inputMode", TypeEnum, Offset(mInputMode, GuiTextEditCtrl), &setInputMode, &getInputMode, &writeInputMode, 1, &gInputModeTable, "InputMode allows different characters to be entered.");
- addField("editCursor", TypeGuiCursor, Offset(mEditCursor, GuiTextEditCtrl));
- endGroup("Text Edit");
- }
- bool GuiTextEditCtrl::onAdd()
- {
- if ( ! Parent::onAdd() )
- return false;
- if( mText[0] )
- {
- setText(mText);
- }
- return true;
- }
- void GuiTextEditCtrl::onStaticModified(const char* slotName)
- {
- if(!dStricmp(slotName, "text"))
- setText(mText);
- }
- void GuiTextEditCtrl::inspectPostApply()
- {
- Parent::inspectPostApply();
- if (mTextID && *mTextID != 0)
- setTextID(mTextID);
- else
- setText(mText);
- }
- bool GuiTextEditCtrl::onWake()
- {
- if (! Parent::onWake())
- return false;
- if (mConsoleVariable[0])
- {
- const char *txt = Con::getVariable(mConsoleVariable);
- if (txt)
- {
- if (dStrlen(txt) > (U32)mMaxStrLen)
- {
- char* buf = new char[mMaxStrLen + 1];
- dStrncpy(buf, txt, mMaxStrLen);
- buf[mMaxStrLen] = 0;
- setScriptValue(buf);
- delete[] buf;
- }
- else
- setScriptValue(txt);
- }
- }
- // If this is the first awake text edit control, enable keyboard translation
- if (smNumAwake == 0)
- Platform::enableKeyboardTranslation();
- ++smNumAwake;
- mSuspendVerticalScrollJump = false;
- return true;
- }
- void GuiTextEditCtrl::onSleep()
- {
- Parent::onSleep();
- // If this is the last awake text edit control, disable keyboard translation
- --smNumAwake;
- if (smNumAwake == 0)
- Platform::disableKeyboardTranslation();
- }
- void GuiTextEditCtrl::execConsoleCallback()
- {
- setVariable(mTextBuffer.c_str());
- if ( mConsoleCommand[0] )
- {
- Con::evaluate( mConsoleCommand, false );
- }
- }
- const char* GuiTextEditCtrl::getText()
- {
- return mTextBuffer.c_str();
- }
-
- void GuiTextEditCtrl::setText( const UTF8 *txt )
- {
- setUpdate();
- enforceMaxLength();
- if (txt && txt[0] != 0)
- {
- Parent::setText(txt);
- mTextBuffer.assign(txt);
- }
- else
- mTextBuffer.clear();
- setVariable(mTextBuffer.c_str());
- }
- void GuiTextEditCtrl::setText( const UTF16* txt)
- {
- if(txt && txt[0] != 0)
- {
- UTF8* txt8 = convertUTF16toUTF8( txt );
- setText(txt8);
- delete[] txt8;
- }
- else
- {
- setText("");
- }
- }
- void GuiTextEditCtrl::enforceMaxLength()
- {
- int diff = mTextBuffer.length() - mMaxStrLen;
- if (diff > 0) {
- mTextBuffer.resize(mMaxStrLen);
- }
- }
- void GuiTextEditCtrl::setTextID(const char *id)
- {
- S32 n = Con::getIntVariable(id, -1);
- if (n != -1)
- {
- setTextID(n);
- }
- }
- void GuiTextEditCtrl::setTextID(S32 id)
- {
- const UTF8 *str = getGUIString(id);
- if (str)
- setText((const char*)str);
- }
- bool GuiTextEditCtrl::validate()
- {
- bool valid = true;
- if (isMethod("onValidate"))
- {
- valid = dAtob(Con::executef(this, 2, "onValidate"));
- }
- return valid;
- }
- const RectI GuiTextEditCtrl::getGlobalInnerRect()
- {
- Point2I offset = Point2I(mBounds.point.Zero);
- Point2I extent = Point2I(getExtent());
- RectI innerRect = getInnerRect(offset, extent, SelectedState, mProfile);
- Point2I globalCtrlOffset = localToGlobalCoord(innerRect.point);
- RectI globalInnerRect(globalCtrlOffset, innerRect.extent);
- return globalInnerRect;
- }
- S32 GuiTextEditCtrl::calculateIbeamPosition(const Point2I& globalMousePoint)
- {
- if (mTextBuffer.length() == 0)
- return 0;
- RectI globalInnerRect = getGlobalInnerRect();
- return calculateIbeamPosition(globalMousePoint, globalInnerRect);
- }
- S32 GuiTextEditCtrl::calculateIbeamPosition(const Point2I& globalMousePoint, const RectI& globalInnerRect)
- {
- if (mTextBuffer.length() == 0 || mTextBlockList.size() == 0)
- return 0;
- string textBuffer = applyPasswordMasking();
- GFont* font = mProfile->getFont(mFontSizeAdjust);
- if (!mTextWrap)
- {
- return mTextBlockList.front().calculateIbeamPositionInLine(globalMousePoint.x, font);
- }
- else
- {
- RectI firstLineBounds = mTextBlockList.front().getGlobalBounds();
- S32 textStartY = firstLineBounds.point.y;
- if (textStartY > globalMousePoint.y)
- return 0;
- U32 height = firstLineBounds.extent.y;
- if ((textStartY + (mTextBlockList.size() * height)) < globalMousePoint.y)
- return mTextBuffer.length();
- S32 curY = textStartY;
- for (auto block : mTextBlockList)
- {
- curY += height;
- if (curY > globalMousePoint.y)
- {
- U32 pos = block.calculateIbeamPositionInLine(globalMousePoint.x, font);
- mSelector.setCursorAtEOL(block.calculateCursorAtEOL(pos));
- return pos + block.getStartValue();
- }
- }
- mSelector.setCursorAtEOL(true);
- return mTextBlockList.back().calculateIbeamPositionInLine(globalMousePoint.x, font);
- }
- }
- void GuiTextEditCtrl::onTouchDown( const GuiEvent &event )
- {
- mScrollVelocity = 0;
- mSuspendVerticalScrollJump = false;
- if (!mVisible || !mAwake)
- return;
- mSelector.setTextLength(mTextBuffer.length());
- if(event.mouseClickCount > 2)
- {
- selectAllText();
- }
- else if(event.mouseClickCount > 1)
- {
- mSelector.selectWholeWord(mTextBuffer);
- }
- else
- {
- S32 newCursorPos = calculateIbeamPosition(event.mousePoint);
- if (event.modifier & SI_SHIFT)
- {
- modifySelectBlock(newCursorPos);
- }
- else
- {
- mSelector.setCursorPosition(newCursorPos);
- }
- }
- mouseLock();
- setFirstResponder();
- mSelector.resetCursorBlink();
- if( isMethod("onTouchDown") )
- {
- char buf[3][32];
- dSprintf(buf[0], 32, "%d", event.modifier);
- dSprintf(buf[1], 32, "%d %d", event.mousePoint.x, event.mousePoint.y);
- dSprintf(buf[2], 32, "%d", event.mouseClickCount);
- Con::executef(this, 4, "onTouchDown", buf[0], buf[1], buf[2]);
- }
- }
- void GuiTextEditCtrl::onTouchDragged( const GuiEvent &event )
- {
- if (!mVisible || !mAwake)
- return;
- mSuspendVerticalScrollJump = false;
- RectI globalInnerRect = getGlobalInnerRect();
- adjustScrollVelocity(event.mousePoint, globalInnerRect);
-
- if ((mTextWrap && event.mousePoint.y < globalInnerRect.point.y) ||
- (!mTextWrap && event.mousePoint.x < globalInnerRect.point.x))
- {
- modifySelectBlock(0);
- }
- else if ((mTextWrap && event.mousePoint.y > (globalInnerRect.point.y + globalInnerRect.extent.y)) ||
- (!mTextWrap && event.mousePoint.x > (globalInnerRect.point.x + globalInnerRect.extent.x)))
- {
- modifySelectBlock(mTextBuffer.length());
- }
- else
- {
- modifySelectBlock(calculateIbeamPosition(event.mousePoint, globalInnerRect));
- }
- // Notify Script.
- if( isMethod("onTouchDragged") )
- {
- char buf[3][32];
- dSprintf(buf[0], 32, "%d", event.modifier);
- dSprintf(buf[1], 32, "%d %d", event.mousePoint.x, event.mousePoint.y);
- dSprintf(buf[2], 32, "%d", event.mouseClickCount);
- Con::executef(this, 4, "onTouchDragged", buf[0], buf[1], buf[2]);
- }
- }
- void GuiTextEditCtrl::onTouchUp(const GuiEvent &event)
- {
- mScrollVelocity = 0;
- mSuspendVerticalScrollJump = false;
- mouseUnlock();
- if (!mVisible || !mAwake)
- return;
- // Notify Script.
- if( isMethod("onTouchUp") )
- {
- char buf[3][32];
- dSprintf(buf[0], 32, "%d", event.modifier);
- dSprintf(buf[1], 32, "%d %d", event.mousePoint.x, event.mousePoint.y);
- dSprintf(buf[2], 32, "%d", event.mouseClickCount);
- Con::executef(this, 4, "onTouchUp", buf[0], buf[1], buf[2]);
- }
- }
- void GuiTextEditCtrl::onMouseWheelUp(const GuiEvent& event)
- {
- if (!mVisible || !mAwake)
- return;
- if(mTextWrap && mTextOffsetY > 0)
- {
- mScrollVelocity = 0;
- mSuspendVerticalScrollJump = true;
- mTextOffsetY = getMax(mTextOffsetY - static_cast<S32>(mProfile->getFont(mFontSizeAdjust)->getHeight()), 0);
- return;
- }
- GuiControl* parent = getParent();
- if (parent)
- parent->onMouseWheelUp(event);
- }
- void GuiTextEditCtrl::onMouseWheelDown(const GuiEvent& event)
- {
- if (!mVisible || !mAwake)
- return;
- U32 blockHeight = mTextBlockList.size() * mProfile->getFont(mFontSizeAdjust)->getHeight();
- RectI innerRect = getGlobalInnerRect();
- S32 max = blockHeight - innerRect.extent.y;
- if (mTextWrap && innerRect.extent.y < blockHeight && mTextOffsetY < max)
- {
- mScrollVelocity = 0;
- mSuspendVerticalScrollJump = true;
- mTextOffsetY = getMin(mTextOffsetY + static_cast<S32>(mProfile->getFont(mFontSizeAdjust)->getHeight()), max);
- return;
- }
- GuiControl* parent = getParent();
- if (parent)
- parent->onMouseWheelDown(event);
- }
- void GuiTextEditCtrl::onTouchEnter(const GuiEvent& event)
- {
- if (!mActive)
- return;
- mMouseOver = true;
- Con::executef(this, 1, "onTouchEnter");
- //update
- setUpdate();
- }
- void GuiTextEditCtrl::onTouchLeave(const GuiEvent& event)
- {
- if (!mActive)
- return;
- mMouseOver = false;
- Con::executef(this, 1, "onTouchLeave");
- //update
- setUpdate();
- }
- void GuiTextEditCtrl::saveUndoState()
- {
- //save the current state
- mUndoText = mTextBuffer;
- mUndoSelector = mSelector;
- }
- void GuiTextEditCtrl::onCopy(bool andCut)
- {
- // Don't copy/cut password field!
- if(mPasswordText)
- return;
- if (mSelector.hasSelection())
- {
- //save the current state
- saveUndoState();
- //copy the text to the clipboard
- string subString = mSelector.getSelection(mTextBuffer);
- Platform::setClipboard(subString.c_str());
- //if we pressed the cut shortcut, we need to cut the selected text from the control...
- if (andCut)
- {
- mSelector.eraseSelection(mTextBuffer);
- }
- mSelector.clearSelection();
- }
- }
- void GuiTextEditCtrl::onPaste()
- {
- //first, make sure there's something in the clipboard to copy...
- string clipboard = Platform::getClipboard();
- if(clipboard.length() <= 0)
- return;
- //save the current state
- saveUndoState();
- //delete anything hilited
- if (mSelector.hasSelection())
- {
- mSelector.eraseSelection(mTextBuffer);
- mSelector.clearSelection();
- }
- U32 pos = mSelector.getCursorPos();
- mTextBuffer.insert(pos, clipboard);
- setText(mTextBuffer);
- pos += clipboard.length();
- mSelector.setCursorPosition(pos);
- execConsoleCallback();
- }
- void GuiTextEditCtrl::onUndo()
- {
- string tempText = mTextBuffer;
- GuiTextEditSelection tempSelector = mSelector;
- mTextBuffer = mUndoText;
- mSelector = mUndoSelector;
- mUndoText = tempText;
- mUndoSelector = tempSelector;
- }
- bool GuiTextEditCtrl::onKeyDown(const GuiEvent &event)
- {
- if(! isActive())
- return false;
- mSuspendVerticalScrollJump = false;
- S32 stringLen = mTextBuffer.length();
- mSelector.setTextLength(stringLen);
- setUpdate();
- bool result = false;
- if (event.modifier & SI_SHIFT)
- {
- result = handleKeyDownWithShift(event);
- }
- else if (event.modifier & SI_CTRL)
- {
- //When holding the ctrl key, events must be handled here or passed up.
- return handleKeyDownWithCtrl(event);
- }
- else if (event.modifier & SI_ALT)
- {
- result = handleKeyDownWithAlt(event);
- #if (defined(TORQUE_OS_OSX) || defined(TORQUE_OS_IOS))
- //Likewise, the cmd key must be handled here or passed up.
- return result;
- #endif
- }
- if(result || (!result && handleKeyDownWithNoModifier(event)))
- {
- return true;
- }
- if (handleCharacterInput(event) || mSinkAllKeyEvents)
- {
- return true;
- }
- return Parent::onKeyDown( event );
- }
- bool GuiTextEditCtrl::tabNext()
- {
- if (isMethod("onTab"))
- Con::executef(this, 2, "onTab", "0");
- GuiCanvas *root = getRoot();
- if (root)
- {
- root->tabNext();
- return true;
- }
- return false;
- }
- bool GuiTextEditCtrl::tabPrev()
- {
- if (isMethod("onTab"))
- Con::executef(this, 2, "onTab", "1");
- GuiCanvas *root = getRoot();
- if (root)
- {
- root->tabPrev();
- return true;
- }
- return false;
- }
- void GuiTextEditCtrl::setFirstResponder()
- {
- mSelector.setFirstResponder(true);
- Parent::setFirstResponder();
-
- #if !defined(TORQUE_OS_IOS) && !defined(TORQUE_OS_ANDROID)
- Platform::enableKeyboardTranslation();
- #endif
- }
- void GuiTextEditCtrl::onLoseFirstResponder()
- {
- Platform::disableKeyboardTranslation();
- //execute the validate command
- bool valid = validate();
- if (valid)
- {
- execAltConsoleCallback();
- }
- if( isMethod( "onLoseFirstResponder" ) )
- Con::executef( this, 2, "onLoseFirstResponder", valid);
- mSelector.setFirstResponder(false);
- mTextOffsetY = 0;
- mScrollVelocity = 0;
- if (!mTextWrap && mTextBlockList.size() > 0)
- {
- mTextBlockList.front().resetScroll();
- }
- // Redraw the control:
- setUpdate();
- }
- void GuiTextEditCtrl::parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent)
- {
- Parent::parentResized( oldParentExtent, newParentExtent );
- mTextOffsetY = 0;
- if (!mTextWrap && mTextBlockList.size() > 0)
- {
- mTextBlockList.front().resetScroll();
- }
- }
- GuiControlState GuiTextEditCtrl::getCurrentState()
- {
- if (!mActive)
- return GuiControlState::DisabledState;
- else if (isFirstResponder())
- return GuiControlState::SelectedState;
- else if (mMouseOver)
- return GuiControlState::HighlightState;
- else
- return GuiControlState::NormalState;
- }
- const ColorI& GuiTextEditCtrl::getCurrentFontColor()
- {
- auto currentState = getCurrentState();
- return mProfile->getFontColor(currentState);
- }
- void GuiTextEditCtrl::onPreRender()
- {
- mSelector.onPreRender(Platform::getVirtualMilliseconds());
- processScrollVelocity();
- }
- void GuiTextEditCtrl::onRender(Point2I offset, const RectI & updateRect)
- {
- GuiControlState currentState = getCurrentState();
- RectI ctrlRect = applyMargins(offset, mBounds.extent, currentState, mProfile);
- renderUniversalRect(ctrlRect, mProfile, currentState);
- //Render Text
- RectI fillRect = applyBorders(ctrlRect.point, ctrlRect.extent, NormalState, mProfile);
- RectI contentRect = applyPadding(fillRect.point, fillRect.extent, NormalState, mProfile);
- if (contentRect.isValidRect())
- {
- if (currentState != SelectedState)
- mSelector.clearSelection();
-
- string textBuffer = applyPasswordMasking();
- renderText(contentRect.point, contentRect.extent, textBuffer.c_str(), mProfile);
- //Render the childen
- renderChildControls(offset, contentRect, updateRect);
- }
- }
- void GuiTextEditCtrl::renderLineList(const Point2I& offset, const Point2I& extent, const S32 startOffsetY, const vector<string> lineList, GuiControlProfile* profile, const TextRotationOptions rot)
- {
- GFont* font = profile->getFont(mFontSizeAdjust);
- const S32 textHeight = font->getHeight();
- S32 totalWidth = extent.x;
- if (mTextBlockList.size() > lineList.size())
- {
- mTextBlockList.resize(lineList.size());
- }
- //Now print each line
- U32 ibeamPos = 0;
- S32 offsetY = startOffsetY - mTextOffsetY;
- for (U32 i = 0; i < lineList.size(); i++)
- {
- if(mTextBlockList.size() <= i)
- {
- mTextBlockList.push_back(GuiTextEditTextBlock());
- }
- Point2I start = Point2I(0, offsetY);
- Point2I blockExtent = Point2I(extent.x, textHeight);
- RectI blockBounds = RectI(start + offset + profile->mTextOffset, blockExtent);
- if (mOverrideFontColor)
- {
- dglSetBitmapModulation(getFontColor(profile, NormalState));
- }
- mTextBlockList[i].render(blockBounds, lineList[i], ibeamPos, mProfile, getCurrentState(), mSelector, getAlignmentType(), font, mOverrideFontColor);
- offsetY += textHeight;
- ibeamPos += lineList[i].length();
- }
- performScrollJumpY();
- }
- void GuiTextEditCtrl::processScrollVelocity()
- {
- if (mScrollVelocity == 0)
- {
- return;
- }
- U32 timeElapsed = Platform::getVirtualMilliseconds() - mTimeLastScrollProcess;
- S32 delta = mRound((F32)(timeElapsed * mScrollVelocity) / 1000);
- if (delta != 0)
- {
- RectI innerRect = getGlobalInnerRect();
- if (mTextWrap)
- {
- U32 max = (mTextBlockList.size() * mProfile->getFont(mFontSizeAdjust)->getHeight()) - innerRect.extent.y;
- mTextOffsetY = mClamp(mTextOffsetY + delta, 0, max);
- }
- else if(mTextBlockList.size() > 0)
- {
- mTextBlockList.front().processScrollVelocity(delta, innerRect.extent.x, mProfile->getFont(mFontSizeAdjust));
- }
- mTimeLastScrollProcess = Platform::getVirtualMilliseconds();
- S32 newCursorPos = calculateIbeamPosition(Canvas->getCursorPos());
- modifySelectBlock(newCursorPos);
- }
- }
- void GuiTextEditCtrl::performScrollJumpY()
- {
- if (mTextWrap && !mSuspendVerticalScrollJump && isFirstResponder() && mSelector.isCursorRendered())
- {
- RectI clipRect = dglGetClipRect();
- S32 areaStart = clipRect.point.y;
- S32 areaEnd = clipRect.point.y + clipRect.extent.y;
- RectI cursorRect = mSelector.getCursorRect();
- S32 lineTop = cursorRect.point.y;
- S32 lineBottom = lineTop + cursorRect.extent.y;
- S32 diff = 0;
- if (lineTop < areaStart)
- {
- diff = lineTop - areaStart;
- }
- else if (lineBottom > areaEnd)
- {
- diff = lineBottom - areaEnd;
- }
- mTextOffsetY += diff;
- }
- }
- void GuiTextEditCtrl::adjustScrollVelocity(const Point2I& globalMousePoint, const RectI& globalInnerRect)
- {
- RectI nonScrollArea = RectI(globalInnerRect);
- if (mTextWrap)
- {
- nonScrollArea.point.y += SCROLL_EDGE_SIZE;
- nonScrollArea.extent.y -= (2 * SCROLL_EDGE_SIZE);
- }
- else
- {
- nonScrollArea.point.x += SCROLL_EDGE_SIZE;
- nonScrollArea.extent.x -= (2 * SCROLL_EDGE_SIZE);
- }
- if (nonScrollArea.pointInRect(globalMousePoint))
- {
- mScrollVelocity = 0;
- }
- else if (globalInnerRect.pointInRect(globalMousePoint))
- {
- if (mScrollVelocity == 0)
- {
- mTimeLastScrollProcess = Platform::getVirtualMilliseconds();
- }
- mScrollVelocity = SCROLL_VELOCITY_PER_SEC;
- if ((mTextWrap && globalMousePoint.y < (globalInnerRect.point.y + SCROLL_EDGE_SIZE)) ||
- (!mTextWrap && globalMousePoint.x < (globalInnerRect.point.x + SCROLL_EDGE_SIZE)))
- {
- mScrollVelocity = -SCROLL_VELOCITY_PER_SEC;
- }
- }
- else
- {
- mScrollVelocity = 0;
- }
- }
- bool GuiTextEditCtrl::hasText()
- {
- return (mTextBuffer.length());
- }
- void GuiTextEditCtrl::keyDenied()
- {
- if (isMethod("onDenied"))
- Con::executef(this, 1, "onDenied");
- }
- const char *GuiTextEditCtrl::getScriptValue()
- {
- return StringTable->insert(mTextBuffer.c_str());
- }
- void GuiTextEditCtrl::setScriptValue(const char *value)
- {
- mTextBuffer.assign(value);
- mSelector.setTextLength(mTextBuffer.length());
- }
- GuiTextEditCtrl::InputMode GuiTextEditCtrl::getInputModeEnum(const char* label)
- {
- // Search for Mnemonic.
- for (U32 i = 0; i < (sizeof(inputModeEnums) / sizeof(EnumTable::Enums)); i++)
- {
- if (dStricmp(inputModeEnums[i].label, label) == 0)
- return (InputMode)inputModeEnums[i].index;
- }
- // Warn.
- Con::warnf("GuiTextEditCtrl::getInputModeEnum() - Invalid mode of '%s'", label);
- return (InputMode)-1;
- }
- const char* GuiTextEditCtrl::getInputModeDescription(const InputMode mode)
- {
- // Search for Mnemonic.
- for (U32 i = 0; i < (sizeof(inputModeEnums) / sizeof(EnumTable::Enums)); i++)
- {
- if (inputModeEnums[i].index == mode)
- return inputModeEnums[i].label;
- }
- // Warn.
- Con::warnf("GuiTextEditCtrl::getInputModeDescription() - Invalid input mode.");
- return StringTable->EmptyString;
- }
- //Returns true if valid, false if invalid
- bool GuiTextEditCtrl::inputModeValidate(const U16 key, S32 cursorPos)
- {
- if (key == '-')
- {
- if (mInputMode == Alpha || mInputMode == AlphaNumeric)
- {
- return false;
- }
- else if (mInputMode == Decimal || mInputMode == Number)
- {
- //a minus sign only exists at the beginning, and only a single minus sign
- if (cursorPos != 0 || (mInsertOn && mTextBuffer[0] == '-'))
- {
- return false;
- }
- }
- }
- else if (key >= '0' && key <= '9')
- {
- if (mInputMode == Alpha)
- {
- return false;
- }
- }
- else if (key == '.')
- {
- if (mInputMode == Number || mInputMode == Alpha || mInputMode == AlphaNumeric)
- {
- return false;
- }
- else if (mInputMode == Decimal)
- {
- if (!mInsertOn && mTextBuffer[cursorPos] == '.')
- {
- return true;
- }
- const char* dot = dStrchr(mTextBuffer.c_str(), '.');
- if (dot != NULL)
- {
- return false;
- }
- }
- }
- else if ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z'))
- {
- if (mInputMode == Decimal || mInputMode == Number)
- {
- return false;
- }
- }
- else if (key == 32)
- {
- if (mInputMode == Decimal || mInputMode == Number)
- {
- return false;
- }
- }
- else if (mInputMode == Decimal || mInputMode == Number || mInputMode == Alpha || mInputMode == AlphaNumeric)
- {
- //The remaining characters only go with AllText
- return false;
- }
- //Looks like we have a valid character!
- return true;
- }
- void GuiTextEditCtrl::setMaxLength(S32 max)
- {
- mMaxStrLen = getMax(1, getMin(max, MAX_STRING_LENGTH));
- }
- void GuiTextEditCtrl::setInputMode(const InputMode mode)
- {
- if(mInputMode == mode)
- return;
- //Time to set the mode
- mInputMode = mode;
- //now let's parse that buffer and get rid of invalid characters
- if (mode != AllText)
- {
- bool oldInsert = mInsertOn;
- mInsertOn = false;
- for (S32 i = 0; i < MAX_STRING_LENGTH; i++)
- {
- const UTF16 character = mTextBuffer[i];
- if (character == '\0')
- {
- //Done and done.
- break;
- }
-
- if (!inputModeValidate(character, i))
- {
- //Bad Character! Let's remove it.
- mTextBuffer.erase(i, 1);
- //Step it back
- i--;
- }
- }
- mInsertOn = oldInsert;
- }
- }
- string GuiTextEditCtrl::applyPasswordMasking()
- {
- if (mPasswordText)
- {
- string passwordCover = string();
- passwordCover.resize(mTextBuffer.length(), mPasswordMask[0]);
- return passwordCover;
- }
- return mTextBuffer;
- }
- bool GuiTextEditCtrl::handleKeyDownWithShift(const GuiEvent& event)
- {
- switch (event.keyCode)
- {
- case KEY_TAB:
- return tabPrev();
- case KEY_HOME:
- mSelector.selectTo(0);
- return true;
- case KEY_END:
- mSelector.selectTo(mTextBuffer.length());
- return true;
- case KEY_LEFT:
- return handleShiftArrowKey(GuiDirection::Left);
- case KEY_RIGHT:
- return handleShiftArrowKey(GuiDirection::Right);
- case KEY_UP:
- return handleShiftArrowKey(GuiDirection::Up);
- case KEY_DOWN:
- return handleShiftArrowKey(GuiDirection::Down);
- }
- return false;
- }
- bool GuiTextEditCtrl::handleKeyDownWithCtrl(const GuiEvent& event)
- {
- switch (event.keyCode)
- {
- #if !(defined(TORQUE_OS_OSX) || defined(TORQUE_OS_IOS))
- // windows style cut / copy / paste / undo keybinds
- case KEY_C:
- case KEY_X:
- onCopy(event.keyCode == KEY_X);
- return true;
- case KEY_V:
- onPaste();
- return true;
- case KEY_Z:
- onUndo();
- return true;
- #endif
- case KEY_DELETE:
- case KEY_BACKSPACE:
- selectAllText();
- handleBackSpace();
- return true;
- }
- return false;
- }
- bool GuiTextEditCtrl::handleKeyDownWithAlt(const GuiEvent& event)
- {
- #if (defined(TORQUE_OS_OSX) || defined(TORQUE_OS_IOS))
- // Added Mac cut/copy/paste/undo keys
- // Mac command key maps to alt in torque.
- switch(event.keyCode)
- {
- case KEY_C:
- case KEY_X:
- onCopy( event.keyCode==KEY_X );
- return true;
-
- case KEY_V:
- onPaste();
- return true;
- case KEY_Z:
- onUndo();
- return true;
- }
- #endif
- return false;
- }
- bool GuiTextEditCtrl::handleKeyDownWithNoModifier(const GuiEvent& event)
- {
- switch (event.keyCode)
- {
- case KEY_TAB:
- return tabNext();
- case KEY_ESCAPE:
- if (mEscapeCommand && mEscapeCommand[0])
- {
- Con::evaluate(mEscapeCommand);
- return true;
- }
- return false;
- case KEY_RETURN:
- case KEY_NUMPADENTER:
- if (!validate())
- {
- return true;
- }
- return handleEnterKey();
- case KEY_LEFT:
- return handleArrowKey(GuiDirection::Left);
- case KEY_RIGHT:
- return handleArrowKey(GuiDirection::Right);
- case KEY_UP:
- return handleArrowKey(GuiDirection::Up);
- case KEY_DOWN:
- return handleArrowKey(GuiDirection::Down);
- case KEY_DELETE:
- return handleDelete();
- case KEY_BACKSPACE:
- return handleBackSpace();
- case KEY_INSERT:
- mInsertOn = !mInsertOn;
- return true;
- case KEY_HOME:
- mSelector.setCursorPosition(0);
- return true;
- case KEY_END:
- mSelector.setCursorPosition(mTextBuffer.length());
- return true;
- }
- return false;
- }
- bool GuiTextEditCtrl::handleCharacterInput(const GuiEvent& event)
- {
- if (!mProfile->getFont(mFontSizeAdjust))
- return false;
- if (mProfile->getFont(mFontSizeAdjust)->isValidChar(event.ascii))
- {
- // Get the character ready to add to a UTF8 string.
- string characterToInsert = string(1, event.ascii);
- //Stop characters that aren't allowed based on InputMode
- if (!inputModeValidate(event.ascii, mSelector.getCursorPos()))
- {
- keyDenied();
- return true;
- }
- saveUndoState();
- if (mSelector.hasSelection())
- {
- mSelector.eraseSelection(mTextBuffer);
- }
- if (mTextBuffer.length() < mMaxStrLen || !mInsertOn)
- {
- if (!mInsertOn)
- {
- mTextBuffer.erase(mSelector.getCursorPos(), 1);
- }
- mTextBuffer.insert(mSelector.getCursorPos(), characterToInsert);
- mSelector.setTextLength(mTextBuffer.length());
- mSelector.stepCursorForward();
- setText(mTextBuffer);
- }
- else
- keyDenied();
- execConsoleCallback();
- return true;
- }
- return false;
- }
- bool GuiTextEditCtrl::handleBackSpace()
- {
- if (mTextBuffer.length() == 0 || (mSelector.getCursorPos() == 0 && !mSelector.hasSelection()))
- return true;
- saveUndoState();
- if (mSelector.hasSelection())
- {
- mSelector.eraseSelection(mTextBuffer);
- }
- else
- {
- mSelector.stepCursorBackward();
- mTextBuffer.erase(mSelector.getCursorPos(), 1);
- }
- mSelector.setTextLength(mTextBuffer.length());
- setText(mTextBuffer);
- execConsoleCallback();
- return true;
- }
- bool GuiTextEditCtrl::handleDelete()
- {
- if (mTextBuffer.length() == mSelector.getCursorPos() && !mSelector.hasSelection())
- return true;
- saveUndoState();
- if (mSelector.hasSelection())
- {
- mSelector.eraseSelection(mTextBuffer);
- }
- else
- {
- mTextBuffer.erase(mSelector.getCursorPos(), 1);
- }
- mSelector.setTextLength(mTextBuffer.length());
- setText(mTextBuffer);
- execConsoleCallback();
- return true;
- }
- bool GuiTextEditCtrl::handleEnterKey()
- {
- if (isMethod("onReturn"))
- Con::executef(this, 1, "onReturn");
- if (mReturnCausesTab)
- {
- tabNext();
- }
-
- if (mReturnCommand && mReturnCommand[0])
- {
- Con::evaluate(mReturnCommand);
- }
- return true;
- }
- bool GuiTextEditCtrl::handleArrowKey(GuiDirection direction)
- {
- if (direction == GuiDirection::Left)
- {
- mSelector.setCursorAtEOL(false);
- mSelector.stepCursorBackward();
- }
- else if (direction == GuiDirection::Right)
- {
- mSelector.setCursorAtEOL(false);
- mSelector.stepCursorForward();
- }
- else if (direction == GuiDirection::Up)
- {
- S32 newCursorPos = getLineAdjustedIbeamPosition(-mProfile->getFont(mFontSizeAdjust)->getHeight());
- if (newCursorPos == mSelector.getCursorPos())
- {
- newCursorPos = 0;
- }
- mSelector.setCursorPosition(newCursorPos);
- }
- else if (direction == GuiDirection::Down)
- {
- S32 newCursorPos = getLineAdjustedIbeamPosition(mProfile->getFont(mFontSizeAdjust)->getHeight());
- if (newCursorPos == mSelector.getCursorPos())
- {
- newCursorPos = mTextBuffer.length();
- }
- mSelector.setCursorPosition(newCursorPos);
- }
- setUpdate();
- mSelector.resetCursorBlink();
- return true;
- }
- bool GuiTextEditCtrl::handleShiftArrowKey(GuiDirection direction)
- {
- if (direction == GuiDirection::Left)
- {
- mSelector.setCursorAtEOL(false);
- modifySelectBlock(mSelector.getCursorPos() - 1);
- }
- else if (direction == GuiDirection::Right)
- {
- mSelector.setCursorAtEOL(false);
- modifySelectBlock(mSelector.getCursorPos() + 1);
- }
- else if (direction == GuiDirection::Up)
- {
- S32 newCursorPos = getLineAdjustedIbeamPosition(-mProfile->getFont(mFontSizeAdjust)->getHeight());
- modifySelectBlock(newCursorPos);
- }
- else if (direction == GuiDirection::Down)
- {
- S32 newCursorPos = getLineAdjustedIbeamPosition(mProfile->getFont(mFontSizeAdjust)->getHeight());
- modifySelectBlock(newCursorPos);
- }
- setUpdate();
- mSelector.resetCursorBlink();
- return true;
- }
- S32 GuiTextEditCtrl::getLineAdjustedIbeamPosition(S32 heightAdjustment)
- {
- Point2I centerPoint = mSelector.getCursorCenter();
- centerPoint.y += heightAdjustment;
- return calculateIbeamPosition(centerPoint);
- }
- void GuiTextEditCtrl::modifySelectBlock(const U32 target)
- {
- mSelector.setTextLength(mTextBuffer.length());
- mSelector.selectTo(target);
- setUpdate();
- }
- void GuiTextEditCtrl::selectAllText()
- {
- mSelector.setCursorPosition(0);
- modifySelectBlock(mTextBuffer.length());
- }
- void GuiTextEditCtrl::getCursor(GuiCursor*& cursor, bool& showCursor, const GuiEvent& lastGuiEvent)
- {
- if (mEditCursor == NULL)
- {
- SimObject* obj;
- obj = Sim::findObject("EditCursor");
- mEditCursor = dynamic_cast<GuiCursor*>(obj);
- }
- if (mEditCursor != NULL)
- {
- cursor = mEditCursor;
- }
- }
- #pragma endregion
|