📄 guimltextctrl.cc
字号:
// change?
mTextBuffer.cut(rangeStart, rangeEnd - rangeStart);
if (mCursorPosition <= rangeStart)
{
// Cursor placed before deleted text, ignore
}
else if (mCursorPosition > rangeStart && mCursorPosition <= rangeEnd)
{
// Cursor inside deleted text, set to start of range
mCursorPosition = rangeStart;
}
else
{
// Cursor after deleted text, decrement by number of chars deleted
mCursorPosition -= (rangeEnd - rangeStart) + 1;
}
AssertFatal(mCursorPosition <= mTextBuffer.length(), "GuiMLTextCtrl::deleteChars: bad cursor position");
mDirty = true;
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::copyToClipboard(const U32 rangeStart, const U32 rangeEnd)
{
AssertFatal(rangeStart < mTextBuffer.length() && rangeEnd < mTextBuffer.length(),
avar("GuiMLTextCtrl::copyToClipboard: can't copy outside of current text (%d, %d, %d)",
rangeStart, rangeEnd, mTextBuffer.length()));
AssertFatal(rangeStart <= rangeEnd, "GuiMLTextCtrl::copyToClipboard: invalid copy range");
//copy the selection to the clipboard
StringBuffer selection = mTextBuffer.substring(rangeStart, rangeEnd-rangeStart);
FrameTemp<UTF8> selBuff(selection.length() * 3 + 1);
selection.get(selBuff, selection.length() * 3 + 1);
Platform::setClipboard(selBuff);
}
//--------------------------------------------------------------------------
bool GuiMLTextCtrl::isSelectionActive() const
{
return mSelectionActive;
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::clearSelection()
{
mSelectionActive = false;
mSelectionStart = 0;
mSelectionEnd = 0;
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::scrollToTag( U32 id )
{
// If the parent control is not a GuiScrollContentCtrl, then this call is invalid:
GuiScrollCtrl *pappy = dynamic_cast<GuiScrollCtrl*>(getParent());
if ( !pappy )
return;
// Find the indicated tag:
LineTag* tag = NULL;
for ( tag = mTagList; tag; tag = tag->next )
{
if ( tag->id == id )
break;
}
if ( !tag )
{
Con::warnf( ConsoleLogEntry::General, "GuiMLTextCtrl::scrollToTag - tag id %d not found!", id );
return;
}
pappy->scrollRectVisible(RectI(0, tag->y, 1, 1));
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::scrollToTop()
{
// If the parent control is not a GuiScrollContentCtrl, then this call is invalid:
GuiScrollCtrl *pappy = dynamic_cast<GuiScrollCtrl*>(getParent());
if ( !pappy )
return;
pappy->scrollRectVisible(RectI(0,0,0,0));
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::scrollToBottom()
{
// If the parent control is not a GuiScrollContentCtrl, then this call is invalid:
GuiScrollCtrl *pappy = dynamic_cast<GuiScrollCtrl*>(getParent());
if ( !pappy )
return;
// Figure bounds for the bottom left corner
RectI cornerBounds (0, getPosition().y + getExtent().y, 1, 1);
pappy->scrollRectVisible(cornerBounds);
}
//--------------------------------------------------------------------------
GuiMLTextCtrl::Atom *GuiMLTextCtrl::findHitAtom(const Point2I localCoords)
{
AssertFatal(mAwake, "Can't get the text position of a sleeping control.");
if(mDirty)
reflow();
for(Line *walk = mLineList; walk; walk = walk->next)
{
if(localCoords.y < walk->y)
return NULL;
if(localCoords.y >= walk->y && localCoords.y < walk->y + walk->height)
{
for(Atom *awalk = walk->atomList; awalk; awalk = awalk->next)
{
if(localCoords.x < awalk->xStart)
return NULL;
if(localCoords.x >= awalk->xStart + awalk->width)
continue;
return awalk;
}
}
}
return NULL;
}
//--------------------------------------------------------------------------
S32 GuiMLTextCtrl::getTextPosition(const Point2I& localCoords)
{
AssertFatal(mAwake, "Can't get the text position of a sleeping control.");
if(mDirty)
reflow();
U32 last = 0;
for(Line *walk = mLineList; walk; walk = walk->next)
{
if((S32)localCoords.y < (S32)walk->y)
return walk->textStart;
if(localCoords.y >= walk->y && localCoords.y < walk->y + walk->height)
{
for(Atom *awalk = walk->atomList; awalk; awalk = awalk->next)
{
if(localCoords.x < awalk->xStart)
return awalk->textStart;
if(localCoords.x >= awalk->xStart + awalk->width)
continue;
// it's in the text block...
U32 x = awalk->xStart;
GFont *font = awalk->style->font->fontRes;
/// Chinese
//FrameTemp<UTF8> tmp( (awalk->textStart - awalk->textStart) * 3 + 1 );
//StringBuffer tmpBuff = mTextBuffer.substring(awalk->textStart, awalk->textStart - awalk->textStart);
//tmpBuff.get(tmp, (awalk->textStart - awalk->textStart) * 3 + 1 );
//U32 bp = font->getBreakPos(tmp, tmpBuff.length(), localCoords.x - awalk->xStart, false);
UTF16* tmp = mTextBuffer.getBuffer(awalk->textStart);
U32 bp = font->getBreakPos(tmp, 1, localCoords.x - awalk->xStart, false);
return awalk->textStart + bp;
}
return walk->textStart + walk->len;
}
}
return mTextBuffer.length() - 1;
}
//--------------------------------------------------------------------------
GuiMLTextCtrl::Font *GuiMLTextCtrl::allocFont(char *faceName, U32 faceNameLen, U32 size)
{
// check if it's in the font list currently:
for(Font *walk = mFontList; walk; walk = walk->next)
if(faceNameLen == walk->faceNameLen &&
!dStrncmp(walk->faceName, faceName, faceNameLen) &&
size == walk->size)
return walk;
// Create!
Font *ret;
ret = constructInPlace((Font *) mResourceChunker.alloc(sizeof(Font)));
ret->faceName = new char[faceNameLen+1];
dStrncpy(ret->faceName, faceName, faceNameLen);
ret->faceName[faceNameLen] = '\0';
ret->faceNameLen = faceNameLen;
ret->size = size;
ret->next = mFontList;
ret->fontRes = GFont::create(ret->faceName, size, GuiControlProfile::sFontCacheDirectory);
if(bool(ret->fontRes))
{
ret->next = mFontList;
mFontList = ret;
return ret;
}
return NULL;
}
#ifdef TGE_RPG
GuiMLTextCtrl::Bitmap *GuiMLTextCtrl::allocIcon(char *iconName, U32 nameLen)
{
STE sBmpName = StringTable->insertn(iconName,nameLen,true);
for(Bitmap *walk = mBitmapList; walk; walk = walk->next)
if(walk->bitmapName == sBmpName)
return walk;
Bitmap *ret = constructInPlace((Bitmap *) mResourceChunker.alloc(sizeof(Bitmap)));
ret->bitmapName = sBmpName;
ret->bmpType = BT_ICON;
RPG::g_pGameIconMan->GetIconTexture(sBmpName,
ret->bitmapHandle,
ret->bmpRect);
if(bool(ret->bitmapHandle))
{
ret->next = mBitmapList;
mBitmapList = ret;
return ret;
}
return NULL;
}
#endif
//--------------------------------------------------------------------------
GuiMLTextCtrl::Bitmap *GuiMLTextCtrl::allocBitmap(char *bitmapName, U32 bitmapNameLen)
{
#ifdef TGE_RPG
STE sBmpName = StringTable->insertn(bitmapName,bitmapNameLen,true);
for(Bitmap *walk = mBitmapList; walk; walk = walk->next)
if(walk->bitmapName == sBmpName)
return walk;
Bitmap *ret = constructInPlace((Bitmap *) mResourceChunker.alloc(sizeof(Bitmap)));
ret->bitmapName = sBmpName;
ret->bmpType = BT_BMP;
//char nameBuffer[256];
//dStrncpy(nameBuffer, bitmapName, bitmapNameLen);
//nameBuffer[bitmapNameLen] = 0;
ret->bitmapHandle = TextureHandle(sBmpName, BitmapTexture);
if(bool(ret->bitmapHandle))
{
ret->bmpRect.set(0,0,ret->bitmapHandle.getWidth(),ret->bitmapHandle.getHeight());
ret->next = mBitmapList;
mBitmapList = ret;
return ret;
}
return NULL;
#else
for(Bitmap *walk = mBitmapList; walk; walk = walk->next)
if(bitmapNameLen == walk->bitmapNameLen &&
!dStrncmp(walk->bitmapName, bitmapName, bitmapNameLen))
return walk;
Bitmap *ret = constructInPlace((Bitmap *) mResourceChunker.alloc(sizeof(Bitmap)));
ret->bitmapName = bitmapName;
ret->bitmapNameLen = bitmapNameLen;
char nameBuffer[256];
dStrncpy(nameBuffer, bitmapName, bitmapNameLen);
nameBuffer[bitmapNameLen] = 0;
ret->bitmapHandle = TextureHandle(nameBuffer, BitmapTexture);
if(bool(ret->bitmapHandle))
{
ret->next = mBitmapList;
mBitmapList = ret;
return ret;
}
return NULL;
#endif
}
//--------------------------------------------------------------------------
GuiMLTextCtrl::LineTag *GuiMLTextCtrl::allocLineTag(U32 id)
{
for ( LineTag* walk = mTagList; walk; walk = walk->next )
{
if ( walk->id == id )
{
Con::warnf( ConsoleLogEntry::General, "GuiMLTextCtrl - can't add duplicate line tags!" );
return( NULL );
}
}
LineTag* newTag = (LineTag*) mViewChunker.alloc( sizeof( LineTag ) );
newTag->id = id;
newTag->y = mCurY;
newTag->next = mTagList;
mTagList = newTag;
return( newTag );
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::emitNewLine(U32 textStart)
{
//clear any clipping
mCurClipX = 0;
Line *l = (Line *) mViewChunker.alloc(sizeof(Line));
#ifdef TGE_RPG
l->height = m_nLineHeightMin > 0 ?
getMax(m_nLineHeightMin,(S32)mCurStyle->font->fontRes->getHeight())
: mCurStyle->font->fontRes->getHeight();
#else
l->height = mCurStyle->font->fontRes->getHeight();
#endif
l->y = mCurY;
l->textStart = mLineStart;
l->len = textStart - l->textStart;
mLineStart = textStart;
l->atomList = mLineAtoms;
l->next = 0;
l->divStyle = mCurDiv;
*mLineInsert = l;
mLineInsert = &(l->next);
mCurX = mCurLMargin;
mCurTabStop = 0;
if(mLineAtoms)
{
// scan through the atoms in the line, get the largest height
U32 maxBaseLine = 0;
U32 maxDescent = 0;
Atom* walk;
for(walk = mLineAtoms; walk; walk = walk->next)
{
if(walk->baseLine > maxBaseLine)
maxBaseLine = walk->baseLine;
if(walk->descent > maxDescent)
maxDescent = walk->descent;
if(!walk->next)
{
l->len = walk->textStart + walk->len - l->textStart;
mLineStart = walk->textStart + walk->len;
}
}
l->height = maxBaseLine + maxDescent;
#ifdef TGE_RPG
l->height = m_nLineHeightMin > 0 ? getMax(m_nLineHeightMin,(S32)l->height) : l->height;
#endif
for(walk = mLineAtoms; walk; walk = walk->next)
walk->yStart = mCurY + maxBaseLine - walk->baseLine;
}
mCurY += l->height;
mLineAtoms = NULL;
mLineAtomPtr = &mLineAtoms;
// clear out the blocker list
BitmapRef **blockList = &mBlockList;
while(*blockList)
{
BitmapRef *blk = *blockList;
if(blk->point.y + blk->extent.y <= mCurY)
*blockList = blk->nextBlocker;
else
blockList = &(blk->nextBlocker);
}
if(mCurY > mMaxY)
mMaxY = mCurY;
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::emitBitmapToken(GuiMLTextCtrl::Bitmap *bmp, U32 textStart, bool bitmapBreak)
{
if(mCurRMargin <= mCurLMargin)
return;
#ifdef TGE_RPG
if(mCurRMargin - mCurLMargin < bmp->bmpRect.extent.x)
return;
#else
if(mCurRMargin - mCurLMargin < bmp->bitmapHandle.getWidth())
return;
#endif
BitmapRef *ref = (BitmapRef *) mViewChunker.alloc(sizeof(BitmapRef));
ref->bitmap = bmp;
ref->next = mBitmapRefList;
mBitmapRefList = ref;
// now we gotta insert it into the blocker list and figure out where it's spos to go...
#ifdef TGE_RPG
ref->extent = bmp->bmpRect.extent;
#else
ref->extent.x = bmp->bitmapHandle.getWidth();
ref->extent.y = bmp->bitmapHandle.getHeight();
#endif
// find the first space in the blocker list that will fit this thats > curLMargin
while(bitmapBreak && mBlockList != &mSentinel)
emitNewLine(textStart);
for(;;)
{
// loop til we find a line that fits...
// we'll have to emitLine repeatedly to clear out the block lists...
BitmapRef **walk = &mBlockList;
U32 minx = mCurX;
U32 maxx = mCurRMargin;
while(*walk)
{
BitmapRef *blk = *walk;
if(blk->point.x > minx)
{
U32 right = maxx;
if(blk->point.x < right)
right = blk->point.x;
U32 width = right - minx;
if(right > minx && width >= ref->extent.x) // we've found the spot...
{
// insert it:
U32 x = minx;
if(mCurJustify == CenterJustify)
x += (width - ref->extent.x) >> 1;
else if(mCurJustify == RightJustify)
x += width - ref->extent.x;
ref->point.x = x;
ref->point.y = mCurY;
ref->nextBlocker = blk;
*walk = ref;
if(ref->point.y + ref->extent.y > mMaxY)
mMaxY = ref->point.y + ref->extent.y;
return;
}
}
if(minx < blk->point.x + blk->extent.x)
minx = blk->point.x + blk->extent.x;
// move on to the next blocker...
walk = &(blk->nextBlocker);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -