📄 guimltextctrl.cc
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "gui/controls/guiMLTextCtrl.h"
#include "gui/containers/guiScrollCtrl.h"
#include "dgl/dgl.h"
#include "console/consoleTypes.h"
#include "gui/core/guiCanvas.h"
#include "core/frameAllocator.h"
#include "core/unicode.h"
#ifdef TGE_RPG
#include "rpg/ui/gameIconMan.h"
#endif
IMPLEMENT_CONOBJECT(GuiMLTextCtrl);
const U32 GuiMLTextCtrl::csmTextBufferGrowthSize = 1024;
ConsoleMethod( GuiMLTextCtrl, setText, void, 3, 3, "(string text)"
"Set the text contained in the control.")
{
object->setText(argv[2], dStrlen(argv[2]));
}
ConsoleMethod( GuiMLTextCtrl, getText, const char*, 2, 2, "Returns the text from the control, including ML.")
{
return( object->getTextContent() );
}
ConsoleMethod( GuiMLTextCtrl, addText, void, 4, 4, "(string text, bool reformat)")
{
object->addText(argv[2], dStrlen(argv[2]), dAtob(argv[3]));
}
ConsoleMethod( GuiMLTextCtrl, setCursorPosition, bool, 3, 3, "(int newPos)"
"Offset in characters to set cursor's position to.")
{
return object->setCursorPosition(dAtoi(argv[2]));
}
ConsoleMethod( GuiMLTextCtrl, scrollToTag, void, 3, 3, "(int tagID)"
"Scroll down to a specified tag.")
{
object->scrollToTag( dAtoi( argv[2] ) );
}
ConsoleMethod( GuiMLTextCtrl, scrollToTop, void, 2, 2, "Scroll to the top of the text.")
{
object->scrollToTop();
}
ConsoleMethod( GuiMLTextCtrl, scrollToBottom, void, 2, 2, "Scroll to the top of the text.")
{
object->scrollToBottom();
}
ConsoleFunction( StripMLControlChars, const char*, 2, 2, "(string val)"
"Strip TorqueML control characters from the specified string, returning a 'clean' version.")
{
return GuiMLTextCtrl::stripControlChars(argv[1]);
}
ConsoleMethod(GuiMLTextCtrl,forceReflow,void,2,2,"forces the text control to reflow the text after new text is added, possibly resizing the control.")
{
if(!object->isAwake())
Con::errorf("GuiMLTextCtrl::forceReflow can only be called on visible controls.");
else
object->reflow();
}
//--------------------------------------------------------------------------
GuiMLTextCtrl::GuiMLTextCtrl()
{
mIsEditCtrl = false;
mCursorPosition = 0;
mMaxBufferSize = -1;
mInitialText = StringTable->insert("");
mSelectionActive = false;
mSelectionStart = 0;
mSelectionEnd = 0;
mLineSpacingPixels = 2;
mAllowColorChars = false;
mBitmapList = 0;
mBitmapRefList = 0;
mFontList = 0;
mDirty = true;
mLineList = 0;
mTagList = 0;
mHitURL = 0;
mActive = true;
mAlpha = 1.0;
#ifdef TGE_RPG
m_nLineHeightMin = 0;
m_nFontDefaultHeight = 12;
m_bCheckCursor = true;
dMemset(m_arCursors,0,sizeof(m_arCursors));
m_cursorType = CT_NORMAL;
m_pCmdScriptFunc = StringTable->getBlank();
#endif
Sim::findObject("InputDeniedSound", mDeniedSound);
}
//--------------------------------------------------------------------------
GuiMLTextCtrl::~GuiMLTextCtrl()
{
mCursorPosition = 0;
mSelectionActive = false;
mSelectionStart = 0;
mSelectionEnd = 0;
freeResources();
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("lineSpacing", TypeS32, Offset(mLineSpacingPixels, GuiMLTextCtrl));
addField("allowColorChars", TypeBool, Offset(mAllowColorChars, GuiMLTextCtrl));
addField("maxChars", TypeS32, Offset(mMaxBufferSize, GuiMLTextCtrl));
addField("deniedSound", TypeAudioProfilePtr, Offset(mDeniedSound, GuiMLTextCtrl));
addField("text", TypeCaseString, Offset( mInitialText, GuiMLTextCtrl ) );
#ifdef TGE_RPG
addField("fontDefaultHeight", TypeS32, Offset(m_nFontDefaultHeight, GuiMLTextCtrl));
addField("lineHeightMin", TypeS32, Offset(m_nLineHeightMin, GuiMLTextCtrl));
addField("cmdFunc", TypeString, Offset( m_pCmdScriptFunc, GuiMLTextCtrl ) );
#endif
}
ConsoleMethod(GuiMLTextCtrl, setAlpha, void, 3, 3, "")
{
object->setAlpha(dAtof(argv[2]));
}
//--------------------------------------------------------------------------
bool GuiMLTextCtrl::onAdd()
{
if(!Parent::onAdd())
return false;
if (!mTextBuffer.length() && mInitialText[0] != 0)
setText(mInitialText, dStrlen(mInitialText)+1);
return true;
}
//--------------------------------------------------------------------------
bool GuiMLTextCtrl::onWake()
{
if (Parent::onWake() == false)
return false;
mDirty = true;
#ifdef TGE_RPG
if(!m_arCursors[CT_URL])
Sim::findObject(CURSOR_HAND_TXT,m_arCursors[CT_URL]);
#endif
return true;
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::onPreRender()
{
if(mDirty)
reflow();
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::drawAtomText(bool sel, U32 start, U32 end, Atom *atom, Line *line, Point2I offset)
{
GFont *font = atom->style->font->fontRes;
U32 xOff = 0;
if(start != atom->textStart)
{
// Get the string in UTF8 for length calcs (this is kinda silly - BJG)
FrameTemp<UTF8> tmp( (start - atom->textStart) * 3 + 1 );
StringBuffer tmpBuff = mTextBuffer.substring(atom->textStart, start - atom->textStart);
tmpBuff.get(tmp, (start - atom->textStart) * 3 + 1 );
xOff += font->getStrNWidth(tmp, start - atom->textStart );
}
Point2I drawPoint(offset.x + atom->xStart + xOff, offset.y + atom->yStart);
ColorI color;
if(atom->url)
{
if(atom->url->mouseDown)
color = atom->style->linkColorHL;
else
color = atom->style->linkColor;
}
else
color = atom->style->color;
/// Chinese
//FrameTemp<UTF8> tmp( (end - start) * 3 + 1 );
//StringBuffer tmpBuff = mTextBuffer.substring(start, end-start);
//tmpBuff.get(tmp, (end - start) * 3 + 1 );
UTF16* tmp = mTextBuffer.getBuffer(start);
if(!sel)
{
if(atom->style->shadowOffset.x || atom->style->shadowOffset.y)
{
ColorI shadowColor = atom->style->shadowColor;
shadowColor.alpha = shadowColor.alpha * mAlpha;
dglSetBitmapModulation(shadowColor);
#ifdef TGE_RPG
if(atom->style->shadowOffset.x)
{
Point2I ptDraw(drawPoint.x + atom->style->shadowOffset.x, drawPoint.y);
dglDrawTextN(font, ptDraw, tmp, end-start, mAllowColorChars ? mProfile->mFontColors : NULL);
ptDraw.x = drawPoint.x - atom->style->shadowOffset.x;
dglDrawTextN(font, ptDraw, tmp, end-start, mAllowColorChars ? mProfile->mFontColors : NULL);
}
if(atom->style->shadowOffset.y)
{
Point2I ptDraw(drawPoint.x , drawPoint.y+ atom->style->shadowOffset.y);
dglDrawTextN(font, ptDraw, tmp, end-start, mAllowColorChars ? mProfile->mFontColors : NULL);
ptDraw.y = drawPoint.y - atom->style->shadowOffset.y;
dglDrawTextN(font, ptDraw, tmp, end-start, mAllowColorChars ? mProfile->mFontColors : NULL);
}
//dglDrawTextN(font, drawPoint + atom->style->shadowOffset, tmp, end-start, mAllowColorChars ? mProfile->mFontColors : NULL);
#else
dglDrawTextN(font, drawPoint + atom->style->shadowOffset, tmp, end-start, mAllowColorChars ? mProfile->mFontColors : NULL);
#endif
}
color.alpha = color.alpha * mAlpha;
dglSetBitmapModulation(color);
dglDrawTextN(font, drawPoint, tmp, end-start, mAllowColorChars ? mProfile->mFontColors : NULL);
//if the atom was "clipped", see if we need to draw a "..." at the end
if (atom->isClipped)
{
Point2I p2 = drawPoint;
p2.x += font->getStrNWidthPrecise(tmp, end-start);
dglDrawTextN(font, p2, "...", 3, mAllowColorChars ? mProfile->mFontColors : NULL);
}
}
else
{
RectI rect;
rect.point.x = drawPoint.x;
rect.point.y = line->y + offset.y;
rect.extent.x = font->getStrNWidth(tmp, end - atom->textStart) + 1;
rect.extent.y = line->height + 1;
dglDrawRectFill(rect, mProfile->mFillColorHL);
dglSetBitmapModulation( mProfile->mFontColorHL ); // over-ride atom color:
dglDrawTextN(font, drawPoint, tmp, end - atom->textStart, mAllowColorChars ? mProfile->mFontColors : NULL);
//if the atom was "clipped", see if we need to draw a "..." at the end
if (atom->isClipped)
{
Point2I p2 = drawPoint;
p2.x += font->getStrNWidthPrecise(tmp, end - atom->textStart);
dglDrawTextN(font, p2, "...", 3, mAllowColorChars ? mProfile->mFontColors : NULL);
}
}
if(atom->url && !atom->url->noUnderline)
{
drawPoint.y += atom->baseLine + 2;
Point2I p2 = drawPoint;
p2.x += font->getStrNWidthPrecise(tmp, end - atom->textStart);
dglDrawLine(drawPoint, p2, color);
}
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::onRender(Point2I offset, const RectI& updateRect)
{
Parent::onRender(offset, updateRect);
// draw all the bitmaps
for(BitmapRef *walk = mBitmapRefList; walk; walk = walk->next)
{
RectI screenBounds = *walk;
screenBounds.point += offset;
if(!screenBounds.overlaps(updateRect))
continue;
dglClearBitmapModulation();
#ifdef TGE_RPG
dglDrawBitmapSR(walk->bitmap->bitmapHandle,screenBounds.point ,walk->bitmap->bmpRect);
#else
dglDrawBitmap(walk->bitmap->bitmapHandle, screenBounds.point);
#endif
//dglDrawRectFill(screenBounds, mProfile->mWallFillColor);
}
// draw all the text and dividerStyles
for(Line *lwalk = mLineList; lwalk; lwalk = lwalk->next)
{
RectI lineRect(offset.x, offset.y + lwalk->y, mBounds.extent.x, lwalk->height);
if(!lineRect.overlaps(updateRect))
continue;
if(lwalk->divStyle)
dglDrawRectFill(lineRect, mProfile->mFillColorHL);
for(Atom *awalk = lwalk->atomList; awalk; awalk = awalk->next)
{
if(!mSelectionActive || mSelectionEnd < awalk->textStart || mSelectionStart >= awalk->textStart + awalk->len)
drawAtomText(false, awalk->textStart, awalk->textStart + awalk->len, awalk, lwalk, offset);
else
{
U32 selectionStart = getMax(awalk->textStart, mSelectionStart);
U32 selectionEnd = getMin(awalk->textStart + awalk->len, mSelectionEnd + 1);
// draw some unselected text
if(selectionStart > awalk->textStart)
drawAtomText(false, awalk->textStart, selectionStart, awalk, lwalk, offset);
// draw the selection
drawAtomText(true, selectionStart, selectionEnd, awalk, lwalk, offset);
if(selectionEnd < awalk->textStart + awalk->len)
drawAtomText(false, selectionEnd, awalk->textStart + awalk->len, awalk, lwalk, offset);
}
}
}
dglClearBitmapModulation();
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::freeLineBuffers()
{
mViewChunker.freeBlocks();
mLineList = NULL;
mBitmapRefList = NULL;
mTagList = NULL;
mHitURL = 0;
mDirty = true;
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::freeResources()
{
for(Font* walk = mFontList; walk; walk = walk->next)
{
delete[] walk->faceName;
walk->fontRes = 0;
}
for(Bitmap* bwalk = mBitmapList; bwalk; bwalk = bwalk->next)
bwalk->bitmapHandle = 0;
mFontList = NULL;
mBitmapList = NULL;
mResourceChunker.freeBlocks();
mDirty = true;
freeLineBuffers();
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::onSleep()
{
freeResources();
Parent::onSleep();
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::inspectPostApply()
{
Parent::inspectPostApply();
if (mInitialText[0] != 0)
setText(mInitialText, dStrlen(mInitialText));
if (mLineSpacingPixels < 0)
mLineSpacingPixels = 0;
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::resize( const Point2I& newPosition, const Point2I& newExtent )
{
Parent::resize( newPosition, newExtent );
//Con::executef( this, 3, "onResize", Con::getIntArg( newExtent.x ), Con::getIntArg( newExtent.y ) );
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::parentResized(const Point2I& oldParentExtent,
const Point2I& newParentExtent)
{
Parent::parentResized(oldParentExtent, newParentExtent);
mDirty = true;
}
//--------------------------------------------------------------------------
U32 GuiMLTextCtrl::getNumChars() const
{
return mTextBuffer.length();
}
//--------------------------------------------------------------------------
U32 GuiMLTextCtrl::getText(char* pBuffer, const U32 bufferSize) const
{
mTextBuffer.get(pBuffer, bufferSize);
return getMin(mTextBuffer.length(), bufferSize);
}
//--------------------------------------------------------------------------
const char* GuiMLTextCtrl::getTextContent()
{
if ( mTextBuffer.length() > 0 )
{
char* returnString = Con::getReturnBuffer( mTextBuffer.length() + 1 );
mTextBuffer.get(returnString, mTextBuffer.length() );
return returnString;
}
return( "" );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -