forked from Mirrors/openclonk
Replace duplicate BreakMessage() implementations
...with a single one based on std::string in the hope of getting rid of StdStrBuf some day.directional-lights
parent
cada67c097
commit
e7f4105b97
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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!
|
||||
|
|
Loading…
Reference in New Issue