Replace duplicate BreakMessage() implementations

...with a single one based on std::string in the hope of getting rid of
StdStrBuf some day.
directional-lights
Lukas Werling 2016-10-22 16:47:50 +02:00
parent cada67c097
commit e7f4105b97
2 changed files with 36 additions and 156 deletions

View File

@ -570,7 +570,6 @@ int CStdFont::BreakMessage(const char *szMsg, int iWdt, char *szOut, int iMaxOut
#ifdef USE_CONSOLE
return 0;
#else
// 2do: Implement this in terms of StdStrBuf-version
// note iMaxOutLen does not include terminating null character
// safety
if (!iMaxOutLen) return 0;
@ -579,145 +578,11 @@ int CStdFont::BreakMessage(const char *szMsg, int iWdt, char *szOut, int iMaxOut
if (szOut) *szOut=0;
return 0;
}
// TODO: might szLastBreakOut, szLastEmergencyBreakPos, szLastEmergencyBreakOut, iXEmergencyBreak not be properly initialised before use?
uint32_t c;
const char *szPos=szMsg, // current parse position in the text
*szLastBreakPos = szMsg, // points to the char after at (whitespace) or after ('-') which text can be broken
*szLastEmergenyBreakPos = NULL, // same, but at last char in case no suitable linebreak could be found
*szLastPos; // last position until which buffer has been transferred to output
char *szLastBreakOut = NULL, *szLastEmergencyBreakOut = NULL; // position of output pointer at break positions
int iX=0, // current text width at parse pos
iXBreak=0, // text width as it was at last break pos
iXEmergencyBreak = 0, // same, but at last char in case no suitable linebreak could be found
iHgt=iLineHgt; // total height of output text
bool fIsFirstLineChar = true;
// ignore any markup
C4Markup MarkupChecker(false);
// go through all text
while (*(szLastPos = szPos))
{
// ignore markup
if (fCheckMarkup) MarkupChecker.SkipTags(&szPos);
// get current char
c = GetNextCharacter(&szPos);
// done? (must check here, because markup-skip may have led to text end)
if (!c) break;
// manual break?
int iCharWdt = 0;
if (c != '\n' && (!fCheckMarkup || c != '|'))
{
// image?
int iImgLgt;
if (fCheckMarkup && c=='{' && szPos[0]=='{' && szPos[1]!='{' && (iImgLgt=SCharPos('}', szPos+1))>0 && szPos[iImgLgt+2]=='}')
{
char imgbuf[101];
SCopy(szPos+1, imgbuf, std::min(iImgLgt, 100));
int iCharHgt;
if(!GetFontImageSize(imgbuf, iCharWdt, iCharHgt))
iCharWdt = 0;
// skip image tag
szPos+=iImgLgt+3;
}
else
{
// regular char
// look up character width in texture coordinates table
if (c >= ' ')
iCharWdt = int(fZoom * GetCharacterFacet(c).Wdt / iFontZoom) + iHSpace;
else
iCharWdt = 0; // OMFG ctrl char
}
// add chars to output
while (szLastPos != szPos)
{
if (szOut)
*szOut++ = *szLastPos++;
else
++szLastPos;
if (szOut && !--iMaxOutLen)
{
// buffer end: cut and terminate
*szOut = '\0';
break;
}
}
if (szOut && !iMaxOutLen) break;
// add to line; always add one char at minimum
if ((iX+=iCharWdt) <= iWdt || fIsFirstLineChar)
{
// check whether linebreak possibility shall be marked here
// 2do: What about unicode-spaces?
if (c<256) if (isspace((unsigned char)c) || c == '-')
{
szLastBreakPos = szPos;
szLastBreakOut = szOut;
// space: Break directly at space if it isn't the first char here
// first char spaces must remain, in case the output area is just one char width
if (c != '-' && !fIsFirstLineChar) --szLastBreakPos; // because c<256, the character length can be safely assumed to be 1 here
iXBreak = iX;
}
// always mark emergency break after char that fitted the line
szLastEmergenyBreakPos = szPos;
iXEmergencyBreak = iX;
szLastEmergencyBreakOut = szOut;
// line OK; continue filling it
fIsFirstLineChar = false;
continue;
}
// line must be broken now
// if there was no linebreak, do it at emergency pos
if (szLastBreakPos == szMsg)
{
szLastBreakPos = szLastEmergenyBreakPos;
szLastBreakOut = szLastEmergencyBreakOut;
iXBreak = iXEmergencyBreak;
}
// insert linebreak at linebreak pos
// was it a space? Then just overwrite space with a linebreak
if (uint8_t(*szLastBreakPos)<128 && isspace((unsigned char)*szLastBreakPos))
*(szLastBreakOut-1) = '\n';
else
{
// otherwise, insert line break
if (szOut && !--iMaxOutLen)
// buffer is full
break;
if (szOut)
{
char *szOut2 = szOut;
while (--szOut2 >= szLastBreakOut)
szOut2[1] = *szOut2;
szOut2[1] = '\n';
}
}
// calc next line usage
iX -= iXBreak;
}
else
{
// a static linebreak: Everything's well; this just resets the line width
iX = 0;
}
// forced or manual line break: set new line beginning to char after line break
szLastBreakPos = szMsg = szPos;
// manual line break or line width overflow: add char to next line
iHgt += iLineHgt;
fIsFirstLineChar = true;
}
// transfer final data to buffer - markup and terminator
if (szOut)
while ((*szOut++ = *szLastPos++))
if (!--iMaxOutLen)
{
// buffer end: cut and terminate
*szOut = '\0';
break;
}
// return text height
return iHgt;
auto t = BreakMessage(szMsg, iWdt, fCheckMarkup, fZoom);
auto str = std::get<0>(t);
auto len = str.copy(szOut, iMaxOutLen);
szOut[len] = '\0';
return std::get<1>(t);
#endif
}
@ -726,20 +591,34 @@ int CStdFont::BreakMessage(const char *szMsg, int iWdt, StdStrBuf *pOut, bool fC
#ifdef USE_CONSOLE
return 0;
#else
// safety
if (!szMsg || !pOut) return 0;
auto t = BreakMessage(szMsg, iWdt, fCheckMarkup, fZoom);
auto str = std::get<0>(t);
pOut->Clear();
pOut->Append(str.c_str(), str.size());
return std::get<1>(t);
#endif
}
// Returns broken message and resulting height.
std::tuple<std::string, int> CStdFont::BreakMessage(const char *szMsg, int iWdt, bool fCheckMarkup, float fZoom)
{
#ifdef USE_CONSOLE
return std::make_tuple("", 0);
#else
if (!szMsg) return std::make_tuple("", 0);
std::string out;
// TODO: might szLastEmergenyBreakPos, iLastBreakOutLen or iXEmergencyBreak not be properly initialised before use?
uint32_t c;
const char *szPos=szMsg, // current parse position in the text
*szLastBreakPos = szMsg, // points to the char after at (whitespace) or after ('-') which text can be broken
*szLastEmergenyBreakPos = NULL, // same, but at last char in case no suitable linebreak could be found
*szLastPos; // last position until which buffer has been transferred to output
*szLastBreakPos = szMsg, // points to the char after at (whitespace) or after ('-') which text can be broken
*szLastEmergenyBreakPos = NULL, // same, but at last char in case no suitable linebreak could be found
*szLastPos; // last position until which buffer has been transferred to output
int iLastBreakOutLen = 0, iLastEmergencyBreakOutLen = 0; // size of output string at break positions
int iX=0, // current text width at parse pos
iXBreak=0, // text width as it was at last break pos
iXEmergencyBreak = 0, // same, but at last char in case no suitable linebreak could be found
iHgt=iLineHgt; // total height of output text
iXBreak=0, // text width as it was at last break pos
iXEmergencyBreak = 0, // same, but at last char in case no suitable linebreak could be found
iHgt=iLineHgt; // total height of output text
int iCharHOverlap = std::max<int>(-iHSpace, 0); // character width exceeding placement of next character
bool fIsFirstLineChar = true;
// ignore any markup
@ -781,7 +660,7 @@ int CStdFont::BreakMessage(const char *szMsg, int iWdt, StdStrBuf *pOut, bool fC
iCharWdt = 0; // OMFG ctrl char
}
// add chars to output
pOut->Append(szLastPos, szPos - szLastPos);
out.append(szLastPos, szPos - szLastPos);
// add to line; always add one char at minimum
if ((iX+=iCharWdt)+iCharHOverlap <= iWdt || fIsFirstLineChar)
{
@ -790,7 +669,7 @@ int CStdFont::BreakMessage(const char *szMsg, int iWdt, StdStrBuf *pOut, bool fC
if (c<256) if (isspace((unsigned char)c) || c == '-')
{
szLastBreakPos = szPos;
iLastBreakOutLen = pOut->getLength();
iLastBreakOutLen = out.size();
// space: Break directly at space if it isn't the first char here
// first char spaces must remain, in case the output area is just one char width
if (c != '-' && !fIsFirstLineChar) --szLastBreakPos; // because c<256, the character length can be safely assumed to be 1 here
@ -799,7 +678,7 @@ int CStdFont::BreakMessage(const char *szMsg, int iWdt, StdStrBuf *pOut, bool fC
// always mark emergency break after char that fitted the line
szLastEmergenyBreakPos = szPos;
iXEmergencyBreak = iX;
iLastEmergencyBreakOutLen = pOut->getLength();
iLastEmergencyBreakOutLen = out.size();
// line OK; continue filling it
fIsFirstLineChar = false;
continue;
@ -810,7 +689,7 @@ int CStdFont::BreakMessage(const char *szMsg, int iWdt, StdStrBuf *pOut, bool fC
if (c<128 && isspace((unsigned char)c))
{
szLastBreakPos = szPos-1;
iLastBreakOutLen = pOut->getLength();
iLastBreakOutLen = out.size();
iXBreak = iX;
}
// if there was no linebreak, do it at emergency pos
@ -823,11 +702,11 @@ int CStdFont::BreakMessage(const char *szMsg, int iWdt, StdStrBuf *pOut, bool fC
// insert linebreak at linebreak pos
// was it a space? Then just overwrite space with a linebreak
if (uint8_t(*szLastBreakPos)<128 && isspace((unsigned char)*szLastBreakPos))
*pOut->getMPtr(iLastBreakOutLen-1) = '\n';
out.at(iLastBreakOutLen-1) = '\n';
else
{
// otherwise, insert line break
pOut->InsertChar('\n', iLastBreakOutLen);
out.insert(iLastBreakOutLen, 1, '\n');
}
// calc next line usage
iX -= iXBreak;
@ -837,7 +716,7 @@ int CStdFont::BreakMessage(const char *szMsg, int iWdt, StdStrBuf *pOut, bool fC
// a static linebreak: Everything's well; this just resets the line width
iX = 0;
// add to output
pOut->Append(szLastPos, szPos - szLastPos);
out.append(szLastPos, szPos - szLastPos);
}
// forced or manual line break: set new line beginning to char after line break
szLastBreakPos = szMsg = szPos;
@ -846,9 +725,9 @@ int CStdFont::BreakMessage(const char *szMsg, int iWdt, StdStrBuf *pOut, bool fC
fIsFirstLineChar = true;
}
// transfer final data to buffer (any missing markup)
pOut->Append(szLastPos, szPos - szLastPos);
out.append(szLastPos, szPos - szLastPos);
// return text height
return iHgt;
return std::make_tuple(out, iHgt);
#endif
}

View File

@ -155,6 +155,7 @@ public:
// Sometimes, only the width of a text is needed
int32_t GetTextWidth(const char *szText, bool fCheckMarkup = true) { int32_t x, y; GetTextExtent(szText, x, y, fCheckMarkup); return x; }
// insert line breaks into a message and return overall height - uses and regards '|' as line breaks
std::tuple<std::string, int> BreakMessage(const char *szMsg, int iWdt, bool fCheckMarkup, float fZoom=1.0f);
int BreakMessage(const char *szMsg, int iWdt, char *szOut, int iMaxOutLen, bool fCheckMarkup, float fZoom=1.0f);
int BreakMessage(const char *szMsg, int iWdt, StdStrBuf *pOut, bool fCheckMarkup, float fZoom=1.0f);
// get message break and pos after message break - does not regard any manual line breaks!