Initial commit
This commit is contained in:
376
Torque/SDK/engine/gui/controls/guiMLTextEditCtrl.cc
Normal file
376
Torque/SDK/engine/gui/controls/guiMLTextEditCtrl.cc
Normal file
@@ -0,0 +1,376 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "gui/controls/guiMLTextEditCtrl.h"
|
||||
#include "gui/containers/guiScrollCtrl.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "platform/event.h"
|
||||
#include "core/frameAllocator.h"
|
||||
#include "core/stringBuffer.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiMLTextEditCtrl);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
GuiMLTextEditCtrl::GuiMLTextEditCtrl()
|
||||
{
|
||||
mEscapeCommand = StringTable->insert( "" );
|
||||
|
||||
mIsEditCtrl = true;
|
||||
|
||||
mActive = true;
|
||||
|
||||
mVertMoveAnchorValid = false;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
GuiMLTextEditCtrl::~GuiMLTextEditCtrl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiMLTextEditCtrl::resize(const Point2I &newPosition, const Point2I &newExtent)
|
||||
{
|
||||
// We don't want to get any smaller than our parent:
|
||||
Point2I newExt = newExtent;
|
||||
GuiControl* parent = getParent();
|
||||
if ( parent )
|
||||
newExt.y = getMax( parent->mBounds.extent.y, newExt.y );
|
||||
|
||||
Parent::resize( newPosition, newExt );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiMLTextEditCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
addField( "escapeCommand", TypeString, Offset( mEscapeCommand, GuiMLTextEditCtrl ) );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Key events...
|
||||
bool GuiMLTextEditCtrl::onKeyDown(const GuiEvent& event)
|
||||
{
|
||||
setUpdate();
|
||||
//handle modifiers first...
|
||||
if (event.modifier & SI_CTRL)
|
||||
{
|
||||
switch(event.keyCode)
|
||||
{
|
||||
//copy/cut
|
||||
case KEY_C:
|
||||
case KEY_X:
|
||||
{
|
||||
//make sure we actually have something selected
|
||||
if (mSelectionActive)
|
||||
{
|
||||
copyToClipboard(mSelectionStart, mSelectionEnd);
|
||||
|
||||
//if we're cutting, also delete the selection
|
||||
if (event.keyCode == KEY_X)
|
||||
{
|
||||
mSelectionActive = false;
|
||||
deleteChars(mSelectionStart, mSelectionEnd);
|
||||
mCursorPosition = mSelectionStart;
|
||||
}
|
||||
else
|
||||
mCursorPosition = mSelectionEnd + 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//paste
|
||||
case KEY_V:
|
||||
{
|
||||
const char *clipBuf = Platform::getClipboard();
|
||||
if (dStrlen(clipBuf) > 0)
|
||||
{
|
||||
// Normal ascii keypress. Go ahead and add the chars...
|
||||
if (mSelectionActive == true)
|
||||
{
|
||||
mSelectionActive = false;
|
||||
deleteChars(mSelectionStart, mSelectionEnd);
|
||||
mCursorPosition = mSelectionStart;
|
||||
}
|
||||
|
||||
insertChars(clipBuf, dStrlen(clipBuf), mCursorPosition);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( event.modifier & SI_SHIFT )
|
||||
{
|
||||
switch ( event.keyCode )
|
||||
{
|
||||
case KEY_TAB:
|
||||
return( Parent::onKeyDown( event ) );
|
||||
}
|
||||
}
|
||||
else if ( event.modifier == 0 )
|
||||
{
|
||||
switch (event.keyCode)
|
||||
{
|
||||
// Escape:
|
||||
case KEY_ESCAPE:
|
||||
if ( mEscapeCommand[0] )
|
||||
{
|
||||
Con::evaluate( mEscapeCommand );
|
||||
return( true );
|
||||
}
|
||||
return( Parent::onKeyDown( event ) );
|
||||
|
||||
// Deletion
|
||||
case KEY_BACKSPACE:
|
||||
case KEY_DELETE:
|
||||
handleDeleteKeys(event);
|
||||
return true;
|
||||
|
||||
// Cursor movement
|
||||
case KEY_LEFT:
|
||||
case KEY_RIGHT:
|
||||
case KEY_UP:
|
||||
case KEY_DOWN:
|
||||
case KEY_HOME:
|
||||
case KEY_END:
|
||||
handleMoveKeys(event);
|
||||
return true;
|
||||
|
||||
// Special chars...
|
||||
case KEY_TAB:
|
||||
// insert 3 spaces
|
||||
if (mSelectionActive == true)
|
||||
{
|
||||
mSelectionActive = false;
|
||||
deleteChars(mSelectionStart, mSelectionEnd);
|
||||
mCursorPosition = mSelectionStart;
|
||||
}
|
||||
insertChars( "\t", 1, mCursorPosition );
|
||||
return true;
|
||||
|
||||
case KEY_RETURN:
|
||||
// insert carriage return
|
||||
if (mSelectionActive == true)
|
||||
{
|
||||
mSelectionActive = false;
|
||||
deleteChars(mSelectionStart, mSelectionEnd);
|
||||
mCursorPosition = mSelectionStart;
|
||||
}
|
||||
insertChars( "\n", 1, mCursorPosition );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.ascii != 0)
|
||||
{
|
||||
// Normal ascii keypress. Go ahead and add the chars...
|
||||
if (mSelectionActive == true)
|
||||
{
|
||||
mSelectionActive = false;
|
||||
deleteChars(mSelectionStart, mSelectionEnd);
|
||||
mCursorPosition = mSelectionStart;
|
||||
}
|
||||
|
||||
UTF8 *outString = NULL;
|
||||
U32 outStringLen = 0;
|
||||
|
||||
#ifdef TORQUE_UNICODE
|
||||
|
||||
UTF16 inData[2] = { event.ascii, 0 };
|
||||
StringBuffer inBuff(inData);
|
||||
|
||||
FrameTemp<UTF8> outBuff(4);
|
||||
inBuff.get(outBuff, 4);
|
||||
|
||||
outString = outBuff;
|
||||
outStringLen = dStrlen(outBuff);
|
||||
#else
|
||||
char ascii = char(event.ascii);
|
||||
outString = &ascii;
|
||||
outStringLen = 1;
|
||||
#endif
|
||||
|
||||
insertChars(outString, outStringLen, mCursorPosition);
|
||||
mVertMoveAnchorValid = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, let the parent have the event...
|
||||
return Parent::onKeyDown(event);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
void GuiMLTextEditCtrl::handleDeleteKeys(const GuiEvent& event)
|
||||
{
|
||||
if ( isSelectionActive() )
|
||||
{
|
||||
mSelectionActive = false;
|
||||
deleteChars(mSelectionStart, mSelectionEnd);
|
||||
mCursorPosition = mSelectionStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ( event.keyCode )
|
||||
{
|
||||
case KEY_BACKSPACE:
|
||||
if (mCursorPosition != 0)
|
||||
{
|
||||
// delete one character left
|
||||
deleteChars(mCursorPosition-1, mCursorPosition-1);
|
||||
setUpdate();
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_DELETE:
|
||||
if (mCursorPosition != mTextBuffer.length())
|
||||
{
|
||||
// delete one character right
|
||||
deleteChars(mCursorPosition, mCursorPosition);
|
||||
setUpdate();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(false, "Unknown key code received!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
void GuiMLTextEditCtrl::handleMoveKeys(const GuiEvent& event)
|
||||
{
|
||||
if ( event.modifier & SI_SHIFT )
|
||||
return;
|
||||
|
||||
mSelectionActive = false;
|
||||
|
||||
switch ( event.keyCode )
|
||||
{
|
||||
case KEY_LEFT:
|
||||
mVertMoveAnchorValid = false;
|
||||
// move one left
|
||||
if ( mCursorPosition != 0 )
|
||||
{
|
||||
mCursorPosition--;
|
||||
setUpdate();
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_RIGHT:
|
||||
mVertMoveAnchorValid = false;
|
||||
// move one right
|
||||
if ( mCursorPosition != mTextBuffer.length() )
|
||||
{
|
||||
mCursorPosition++;
|
||||
setUpdate();
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_UP:
|
||||
case KEY_DOWN:
|
||||
{
|
||||
Line* walk;
|
||||
for ( walk = mLineList; walk->next; walk = walk->next )
|
||||
{
|
||||
if ( mCursorPosition <= ( walk->textStart + walk->len ) )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !walk )
|
||||
return;
|
||||
|
||||
if ( event.keyCode == KEY_UP )
|
||||
{
|
||||
if ( walk == mLineList )
|
||||
return;
|
||||
}
|
||||
else if ( walk->next == NULL )
|
||||
return;
|
||||
|
||||
Point2I newPos;
|
||||
newPos.set( 0, walk->y );
|
||||
|
||||
// Find the x-position:
|
||||
if ( !mVertMoveAnchorValid )
|
||||
{
|
||||
Point2I cursorTopP, cursorBottomP;
|
||||
ColorI color;
|
||||
getCursorPositionAndColor(cursorTopP, cursorBottomP, color);
|
||||
mVertMoveAnchor = cursorTopP.x;
|
||||
mVertMoveAnchorValid = true;
|
||||
}
|
||||
|
||||
newPos.x = mVertMoveAnchor;
|
||||
|
||||
// Set the new y-position:
|
||||
if (event.keyCode == KEY_UP)
|
||||
newPos.y--;
|
||||
else
|
||||
newPos.y += (walk->height + 1);
|
||||
|
||||
if (setCursorPosition(getTextPosition(newPos)))
|
||||
mVertMoveAnchorValid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case KEY_HOME:
|
||||
case KEY_END:
|
||||
{
|
||||
mVertMoveAnchorValid = false;
|
||||
Line* walk;
|
||||
for (walk = mLineList; walk->next; walk = walk->next)
|
||||
{
|
||||
if (mCursorPosition <= (walk->textStart + walk->len))
|
||||
break;
|
||||
}
|
||||
|
||||
if (walk)
|
||||
{
|
||||
if (event.keyCode == KEY_HOME)
|
||||
{
|
||||
//place the cursor at the beginning of the first atom if there is one
|
||||
if (walk->atomList)
|
||||
mCursorPosition = walk->atomList->textStart;
|
||||
else
|
||||
mCursorPosition = walk->textStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCursorPosition = walk->textStart;
|
||||
mCursorPosition += walk->len;
|
||||
}
|
||||
setUpdate();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
AssertFatal(false, "Unknown move key code was received!");
|
||||
}
|
||||
|
||||
ensureCursorOnScreen();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiMLTextEditCtrl::onRender(Point2I offset, const RectI& updateRect)
|
||||
{
|
||||
Parent::onRender(offset, updateRect);
|
||||
|
||||
// We are the first responder, draw our cursor in the appropriate position...
|
||||
if (isFirstResponder())
|
||||
{
|
||||
Point2I top, bottom;
|
||||
ColorI color;
|
||||
getCursorPositionAndColor(top, bottom, color);
|
||||
dglDrawLine(top + offset, bottom + offset, mProfile->mCursorColor);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user