diff --git a/src/graphics/C4FontLoader.cpp b/src/graphics/C4FontLoader.cpp index d352e90cd..46612de33 100644 --- a/src/graphics/C4FontLoader.cpp +++ b/src/graphics/C4FontLoader.cpp @@ -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 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(-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 } diff --git a/src/graphics/C4FontLoader.h b/src/graphics/C4FontLoader.h index c3d17f2d5..8aa01c031 100644 --- a/src/graphics/C4FontLoader.h +++ b/src/graphics/C4FontLoader.h @@ -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 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!