📄 guimltextctrl.cc
字号:
// go to the next line...
emitNewLine(textStart);
}
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::emitTextToken(U32 textStart, U32 len)
{
if(mCurRMargin <= mCurLMargin)
return;
GFont *font = mCurStyle->font->fontRes;
Atom *a = (Atom *) mViewChunker.alloc(sizeof(Atom));
a->url = mCurURL;
a->style = mCurStyle;
mCurStyle->used = true;
a->baseLine = font->getBaseline();
a->descent = font->getDescent();
a->textStart = textStart;
a->len = len;
a->isClipped = false;
a->next = NULL;
*mEmitAtomPtr = a;
mEmitAtomPtr = &(a->next);
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::processEmitAtoms()
{
Atom *atomList = mEmitAtoms;
mEmitAtoms = NULL;
mEmitAtomPtr = &mEmitAtoms;
while(atomList)
{
// split the tokenlist by space
// first find the first space that the text can go into:
BitmapRef *br = mBlockList;
bool bailout = false;
Atom *list = atomList;
while(br && atomList)
{
// if the blocker is before the current x, ignore it.
if(br->point.x + br->extent.x <= mCurX)
{
br = br->nextBlocker;
continue;
}
// if cur x is in the middle of the blocker
// advance cur x to right edge of blocker.
if(mCurX >= br->point.x)
{
mCurX = br->point.x + br->extent.x;
br = br->nextBlocker;
continue;
}
// get the remaining width
U32 right = br->point.x;
if(right > mCurRMargin)
right = mCurRMargin;
//if we're clipping text, readjust
if (mCurClipX > 0 && right > mCurClipX)
right = mCurClipX;
// if there's no room, break to the next line...
if(right <= mCurX)
break;
// we've got some space:
U32 width = right - mCurX;
atomList = splitAtomListEmit(atomList, width);
if(atomList) // there's more, so advance cur x
{
mCurX = br->point.x + br->extent.x;
br = br->nextBlocker;
}
}
if(mBlockList == &mSentinel && atomList == list)
{
if(bailout)
return;
else
bailout = true;
}
// is there more to process for the next line?
if(atomList)
emitNewLine(mScanPos);
}
}
//--------------------------------------------------------------------------
GuiMLTextCtrl::Atom *GuiMLTextCtrl::splitAtomListEmit(Atom *list, U32 width)
{
//取消emitted功能,则造成死循环
#define TGE_RPG_MLTEXT
U32 totalWidth = 0;
Atom *emitList = 0;
Atom **emitPtr = &emitList;
bool adjustClipAtom = false;
Atom *clipAtom = NULL;
//#ifdef TGE_RPG_MLTEXT
bool emitted = false;
//#endif
while(list)
{
GFont *font = list->style->font->fontRes;
U32 breakPos;
/// Chinese
//FrameTemp<UTF8> tmp( (list->len) * 3 + 1 );
//StringBuffer tmpBuff = mTextBuffer.substring(list->textStart, list->len);
//tmpBuff.get(tmp, (list->len) * 3 + 1 );
UTF16* tmp = mTextBuffer.getBuffer(list->textStart);
//if we're clipping the text, we don't break within an atom, we adjust the atom to only render
//the portion of text that does fit, and to ignore the rest...
if (mCurClipX > 0)
{
//find out how many character's fit within the given width
/// Chinese
breakPos = font->getBreakPos(tmp, list->len, width - totalWidth, false);
//if there isn't room for even the first character...
if (breakPos == 0)
{
//set the atom's len and width to prevent it from being drawn
list->len = 0;
list->width = 0;
adjustClipAtom = true;
}
//if our text doesn't fit within the clip region, add a "..."
else if (breakPos != list->len)
{
U32 etcWidth = font->getStrNWidthPrecise("...", 3);
breakPos = font->getBreakPos(tmp, list->len, width - totalWidth - etcWidth, false);
//again, if there isn't even room for a single character before the "...."
if (breakPos == 0)
{
//set the atom's len and width to prevent it from being drawn
list->len = 0;
list->width = 0;
adjustClipAtom = true;
}
else
{
//set the char len to the break pos, and the rest of the characters in this atom will be ignored
list->len = breakPos;
list->width = width - totalWidth;
//mark this one as clipped
list->isClipped = true;
clipAtom = NULL;
}
}
//otherwise no need to treat this atom any differently..
else
{
//set the atom width == to the string length
list->width = font->getStrNWidthPrecise(tmp, breakPos);
//set the pointer to the last atom that fit within the clip region
clipAtom = list;
}
}
else
{
breakPos = font->getBreakPos(tmp, list->len, width - totalWidth, false);
#ifdef TGE_RPG_MLTEXT
if(breakPos == 0
|| (breakPos < list->len && emitted))
#else
if(breakPos == 0 || (breakPos < list->len && mTextBuffer.getChar(list->textStart + breakPos - 1)!= ' ' && emitted))
#endif
break;
//set the atom width == to the string length
list->width = font->getStrNWidthPrecise(tmp, breakPos);
}
//update the total width
totalWidth += list->width;
// see if this is the last atom that will fit:
Atom *emit = list;
*emitPtr = emit;
emitPtr = &(emit->next);
#ifdef TGE_RPG_MLTEXT
if(totalWidth >= width)
emitted = true;
#else
emitted = true;
#endif
//if we're clipping, don't split the atom, otherwise, see if it needs to be split
if(!list->isClipped && breakPos != list->len)
{
Atom *a = (Atom *) mViewChunker.alloc(sizeof(Atom));
a->url = list->url;
a->textStart = list->textStart + breakPos;
a->len = list->len - breakPos;
a->next = list->next;
a->baseLine = list->baseLine;
a->descent = list->descent;
a->style = list->style;
a->isClipped = false;
list = a;
emit->len = breakPos;
break;
}
list = list->next;
if(totalWidth > width)
break;
}
//if we had to completely clip an atom(s), the last (partially) visible atom should be modified to include a "..."
if (adjustClipAtom && clipAtom)
{
GFont *font = clipAtom->style->font->fontRes;
U32 breakPos;
U32 etcWidth = font->getStrNWidthPrecise("...", 3);
/// Chinese
//FrameTemp<UTF8> tmp( (clipAtom->len) * 3 + 1 );
//StringBuffer tmpBuff = mTextBuffer.substring(clipAtom->textStart, clipAtom->len);
//tmpBuff.get(tmp, (clipAtom->len) * 3 + 1 );
UTF16* tmp = mTextBuffer.getBuffer(clipAtom->textStart);
breakPos = font->getBreakPos(tmp, clipAtom->len, clipAtom->width - etcWidth, false);
if (breakPos != 0)
{
clipAtom->isClipped = true;
clipAtom->len = breakPos;
}
}
// terminate the emit list:
*emitPtr = 0;
// now emit it:
// going from mCurX to mCurX + width:
if(mCurJustify == CenterJustify)
{
if ( width > totalWidth )
mCurX += (width - totalWidth) >> 1;
}
else if(mCurJustify == RightJustify)
{
if ( width > totalWidth )
mCurX += width - totalWidth;
}
while(emitList)
{
emitList->xStart = mCurX;
mCurX += emitList->width;
Atom *temp = emitList->next;
*mLineAtomPtr = emitList;
emitList->next = 0;
mLineAtomPtr = &(emitList->next);
emitList = temp;
}
return list;
}
//--------------------------------------------------------------------------
#ifdef TGE_CHINESE
//需要考虑GB码为双字节
static bool scanforchar(char *str, U32 &idx, char c,U32* pGBNum=NULL)
{
U32 startidx = idx;
U32 nGBNum = 0;
while(str[idx] != c && str[idx] && str[idx] != ':' && str[idx] != '>' && str[idx] != '\n')
{
if(IsGB(str[idx]))
{
nGBNum++;
idx+=2;
}
else
idx++;
}
if(pGBNum)
*pGBNum += nGBNum;
return str[idx] == c && startidx != idx;
}
#else
static bool scanforchar(char *str, U32 &idx, char c)
{
U32 startidx = idx;
while(str[idx] != c && str[idx] && str[idx] != ':' && str[idx] != '>' && str[idx] != '\n')
idx++;
return str[idx] == c && startidx != idx;
}
#endif
//--------------------------------------------------------------------------
static S32 getHexVal(char c)
{
if(c >= '0' && c <= '9')
return c - '0';
else if(c >= 'A' && c <= 'Z')
return c - 'A' + 10;
else if(c >= 'a' && c <= 'z')
return c - 'a' + 10;
return -1;
}
//--------------------------------------------------------------------------
GuiMLTextCtrl::Style *GuiMLTextCtrl::allocStyle(GuiMLTextCtrl::Style *style)
{
Style *ret = (Style *) mViewChunker.alloc(sizeof(Style));
ret->used = false;
if(style)
{
ret->font = style->font;
ret->color = style->color;
ret->linkColor = style->linkColor;
ret->linkColorHL = style->linkColorHL;
ret->shadowColor = style->shadowColor;
ret->shadowOffset = style->shadowOffset;
ret->next = style->next;
}
else
{
ret->font = 0;
ret->next = 0;
}
return ret;
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::reflow()
{
AssertFatal(mAwake, "Can't reflow a sleeping control.");
freeLineBuffers();
mDirty = false;
mScanPos = 0;
mLineList = NULL;
mLineInsert = &mLineList;
mCurStyle = allocStyle(NULL);
mCurStyle->font = allocFont((char *) mProfile->mFontType, dStrlen(mProfile->mFontType), mProfile->mFontSize);
if(!mCurStyle->font)
return;
mCurStyle->color = mProfile->mFontColor;
mCurStyle->shadowColor = mProfile->mFontColor;
mCurStyle->shadowOffset.set(0,0);
mCurStyle->linkColor = mProfile->mFontColors[GuiControlProfile::ColorUser0];
mCurStyle->linkColorHL = mProfile->mFontColors[GuiControlProfile::ColorUser1];
U32 width = mBounds.extent.x;
mCurLMargin = 0;
mCurRMargin = width;
mCurJustify = LeftJustify;
mCurDiv = 0;
mCurY = 0;
mCurX = 0;
mCurClipX = 0;
mLineAtoms = NULL;
mLineAtomPtr = &mLineAtoms;
mSentinel.point.x = width;
mSentinel.point.y = 0;
mSentinel.extent.x = 0;
mSentinel.extent.y = 0x7FFFFF;
mSentinel.nextBlocker = NULL;
mLineStart = 0;
mEmitAtoms = 0;
mMaxY = 0;
mEmitAtomPtr = &mEmitAtoms;
mBlockList = &mSentinel;
Font *nextFont;
LineTag *nextTag;
mTabStops = 0;
mCurTabStop = 0;
mTabStopCount = 0;
mCurURL = 0;
Style *newStyle;
U32 textStart;
U32 len;
U32 idx;
U32 sizidx;
for(;;)
{
UTF16 curChar = mTextBuffer.getChar(mScanPos);
if(!curChar)
break;
if(curChar == '\n')
{
textStart = mScanPos;
len = 1;
mScanPos++;
processEmitAtoms();
emitNewLine(textStart);
mCurDiv = 0;
continue;
}
if(curChar == '\t')
{
textStart = mScanPos;
len = 1;
mScanPos++;
processEmitAtoms();
#ifdef TGE_RPG
U32 nWidth;
if(m_nFontDefaultHeight== 0)
{
if(mTabStopCount)
{
if(mCurTabStop < mTabStopCount)
{
nWidth = mTabStops[mCurTabStop];
if(mCurX - mCurLMargin < nWidth)
mCurX = mCurLMargin + nWidth;
mCurTabStop++;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -