📄 guitexteditctrl.cc
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "console/consoleTypes.h"
#include "console/console.h"
#include "dgl/dgl.h"
#include "gui/core/guiCanvas.h"
#include "gui/controls/guiMLTextCtrl.h"
#include "gui/controls/guiTextEditCtrl.h"
#include "gui/core/guiDefaultControlRender.h"
#include "core/frameAllocator.h"
IMPLEMENT_CONOBJECT(GuiTextEditCtrl);
U32 GuiTextEditCtrl::smNumAwake = 0;
GuiTextEditCtrl::GuiTextEditCtrl()
{
mInsertOn = true;
mBlockStart = 0;
mBlockEnd = 0;
mCursorPos = 0;
mCursorOn = false;
mNumFramesElapsed = 0;
mDragHit = false;
mTabComplete = false;
mScrollDir = 0;
mUndoBlockStart = 0;
mUndoBlockEnd = 0;
mUndoCursorPos = 0;
mPasswordText = false;
mSinkAllKeyEvents = false;
mActive = true;
mTextOffsetReset = true;
#ifdef TGE_RPG
mCursorOffset.set(0,0);
#endif
mHistoryDirty = false;
mHistorySize = 0;
mHistoryLast = -1;
mHistoryIndex = 0;
mHistoryBuf = NULL;
mValidateCommand = StringTable->insert("");
mEscapeCommand = StringTable->insert( "" );
mPasswordMask = StringTable->insert( "*" );
mDeniedSound = dynamic_cast<AudioProfile*>( Sim::findObject( "InputDeniedSound" ) );
mEditCursor = NULL;
}
GuiTextEditCtrl::~GuiTextEditCtrl()
{
//delete the history buffer if it exists
if (mHistoryBuf)
{
for (S32 i = 0; i < mHistorySize; i++)
delete [] mHistoryBuf[i];
delete [] mHistoryBuf;
}
}
void GuiTextEditCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("validate", TypeString, Offset(mValidateCommand, GuiTextEditCtrl));
addField("escapeCommand", TypeString, Offset(mEscapeCommand, GuiTextEditCtrl));
addField("historySize", TypeS32, Offset(mHistorySize, GuiTextEditCtrl));
addField("password", TypeBool, Offset(mPasswordText, GuiTextEditCtrl));
addField("tabComplete", TypeBool, Offset(mTabComplete, GuiTextEditCtrl));
addField("deniedSound", TypeAudioProfilePtr, Offset(mDeniedSound, GuiTextEditCtrl));
addField("sinkAllKeyEvents", TypeBool, Offset(mSinkAllKeyEvents, GuiTextEditCtrl));
addField("password", TypeBool, Offset(mPasswordText, GuiTextEditCtrl));
addField("passwordMask", TypeString, Offset(mPasswordMask, GuiTextEditCtrl));
}
bool GuiTextEditCtrl::onAdd()
{
if ( ! Parent::onAdd() )
return false;
//create the history buffer
if ( mHistorySize > 0 )
{
mHistoryBuf = new UTF8*[mHistorySize];
for ( S32 i = 0; i < mHistorySize; i++ )
{
mHistoryBuf[i] = new UTF8[GuiTextCtrl::MAX_STRING_LENGTH + 1];
mHistoryBuf[i][0] = '\0';
}
}
setText(mText);
return true;
}
void GuiTextEditCtrl::onStaticModified(const char* slotName)
{
if(!dStricmp(slotName, "text"))
setText(mText);
}
bool GuiTextEditCtrl::onWake()
{
if (! Parent::onWake())
return false;
// If this is the first awake text edit control, enable keyboard translation
if (smNumAwake == 0)
Platform::enableKeyboardTranslation();
++smNumAwake;
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()
{
// Execute the console command!
if ( mConsoleCommand[0] )
{
char buf[16];
dSprintf( buf, sizeof( buf ), "%d", getId() );
Con::setVariable( "$ThisControl", buf );
Con::evaluate( mConsoleCommand, false );
}
// Update the console variable:
UTF8 buffer[1024];
mTextBuffer.get(buffer, 1024);
if ( mConsoleVariable[0] )
Con::setVariable( mConsoleVariable, (char*)buffer );
}
void GuiTextEditCtrl::updateHistory( StringBuffer *inTxt, bool moveIndex )
{
FrameTemp<UTF8> textString(inTxt->length()*3 + 1);
inTxt->get(textString, inTxt->length()*3 + 1);
UTF8 *txt = textString;
if(!txt)
return;
if(!mHistorySize)
return;
// see if it's already in
if(mHistoryLast == -1 || dStrcmp((const UTF8*)txt, (const UTF8*)mHistoryBuf[mHistoryLast]))
{
if(mHistoryLast == mHistorySize-1) // we're at the history limit... shuffle the pointers around:
{
UTF8 *first = mHistoryBuf[0];
for(U32 i = 0; i < mHistorySize - 1; i++)
mHistoryBuf[i] = mHistoryBuf[i+1];
mHistoryBuf[mHistorySize-1] = first;
if(mHistoryIndex > 0)
mHistoryIndex--;
}
else
mHistoryLast++;
inTxt->get(mHistoryBuf[mHistoryLast], GuiTextCtrl::MAX_STRING_LENGTH);
mHistoryBuf[mHistoryLast][GuiTextCtrl::MAX_STRING_LENGTH] = '\0';
}
if(moveIndex)
mHistoryIndex = mHistoryLast + 1;
}
void GuiTextEditCtrl::getText( char *dest )
{
if ( dest )
mTextBuffer.get((UTF8*)dest, GuiTextCtrl::MAX_STRING_LENGTH+1);
}
void GuiTextEditCtrl::setText( const char *txt )
{
Parent::setText( txt );
if(txt && txt[0] != 0)
mTextBuffer.set( txt );
else
mTextBuffer.set( "" );
mCursorPos = mTextBuffer.length();
}
void GuiTextEditCtrl::reallySetCursorPos( const S32 newPos )
{
S32 charCount = mTextBuffer.length();
S32 realPos = newPos > charCount ? charCount : newPos < 0 ? 0 : newPos;
if ( realPos != mCursorPos )
{
mCursorPos = realPos;
setUpdate();
}
}
S32 GuiTextEditCtrl::setCursorPos( const Point2I &offset )
{
Point2I ctrlOffset = localToGlobalCoord( Point2I( 0, 0 ) );
S32 charCount = mTextBuffer.length();
S32 charLength = 0;
S32 curX;
curX = offset.x - ctrlOffset.x;
setUpdate();
//if the cursor is too far to the left
if ( curX < 0 )
return -1;
//if the cursor is too far to the right
if ( curX >= ctrlOffset.x + mBounds.extent.x )
return -2;
curX = offset.x - mTextOffset.x;
S32 count=0;
if(mTextBuffer.length())
{
for(count=0; count<mTextBuffer.length(); count++)
{
charLength += mFont->getCharXIncrement( mTextBuffer.getChar(count) );
if ( charLength > curX )
break;
}
}
return count;
}
void GuiTextEditCtrl::onMouseDown( const GuiEvent &event )
{
mDragHit = false;
//undo any block function
mBlockStart = 0;
mBlockEnd = 0;
//find out where the cursor should be
S32 pos = setCursorPos( event.mousePoint );
// if the position is to the left
if ( pos == -1 )
mCursorPos = 0;
else if ( pos == -2 ) //else if the position is to the right
mCursorPos = mTextBuffer.length();
else //else set the mCursorPos
mCursorPos = pos;
//save the mouseDragPos
mMouseDragStart = mCursorPos;
// lock the mouse
mouseLock();
//set the drag var
mDragHit = true;
//let the parent get the event
setFirstResponder();
}
void GuiTextEditCtrl::onMouseDragged( const GuiEvent &event )
{
S32 pos = setCursorPos( event.mousePoint );
// if the position is to the left
if ( pos == -1 )
mScrollDir = -1;
else if ( pos == -2 ) // the position is to the right
mScrollDir = 1;
else // set the new cursor position
{
mScrollDir = 0;
mCursorPos = pos;
}
// update the block:
mBlockStart = getMin( mCursorPos, mMouseDragStart );
mBlockEnd = getMax( mCursorPos, mMouseDragStart );
if ( mBlockStart < 0 )
mBlockStart = 0;
if ( mBlockStart == mBlockEnd )
mBlockStart = mBlockEnd = 0;
//let the parent get the event
Parent::onMouseDragged(event);
}
void GuiTextEditCtrl::onMouseUp(const GuiEvent &event)
{
event;
mDragHit = false;
mScrollDir = 0;
mouseUnlock();
}
void GuiTextEditCtrl::saveUndoState()
{
//save the current state
mUndoText.set(&mTextBuffer);
mUndoBlockStart = mBlockStart;
mUndoBlockEnd = mBlockEnd;
mUndoCursorPos = mCursorPos;
}
bool GuiTextEditCtrl::onKeyDown(const GuiEvent &event)
{
S32 stringLen = mTextBuffer.length();
setUpdate();
// Ugly, but now I'm cool like MarkF.
if(event.keyCode == KEY_BACKSPACE)
goto dealWithBackspace;
if (event.modifier & SI_SHIFT)
{
switch (event.keyCode)
{
case KEY_TAB:
if ( mTabComplete )
{
Con::executef( this, 2, "onTabComplete", "1" );
return( true );
}
case KEY_HOME:
mBlockStart = 0;
mBlockEnd = mCursorPos;
mCursorPos = 0;
return true;
case KEY_END:
mBlockStart = mCursorPos;
mBlockEnd = stringLen;
mCursorPos = stringLen;
return true;
case KEY_LEFT:
if ((mCursorPos > 0) & (stringLen > 0))
{
//if we already have a selected block
if (mCursorPos == mBlockEnd)
{
mCursorPos--;
mBlockEnd--;
if (mBlockEnd == mBlockStart)
{
mBlockStart = 0;
mBlockEnd = 0;
}
}
else {
mCursorPos--;
mBlockStart = mCursorPos;
if (mBlockEnd == 0)
{
mBlockEnd = mCursorPos + 1;
}
}
}
return true;
case KEY_RIGHT:
if (mCursorPos < stringLen)
{
if ((mCursorPos == mBlockStart) && (mBlockEnd > 0))
{
mCursorPos++;
mBlockStart++;
if (mBlockStart == mBlockEnd)
{
mBlockStart = 0;
mBlockEnd = 0;
}
}
else
{
if (mBlockEnd == 0)
{
mBlockStart = mCursorPos;
mBlockEnd = mCursorPos;
}
mCursorPos++;
mBlockEnd++;
}
}
return true;
}
}
else if (event.modifier & SI_CTRL)
{
switch(event.keyCode)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -