mirror of
https://github.com/vcmi/vcmi.git
synced 2025-09-16 09:26:28 +02:00
- chinese fonts now use fallback to H3 fonts for ASCII characters
- proper messages for not implemented main menu entries - some cleanup of CMessage::breakText()
This commit is contained in:
@@ -129,44 +129,54 @@ SDL_Surface * CMessage::drawDialogBox(int w, int h, PlayerColor playerColor)
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> CMessage::breakText( std::string text, size_t maxLineSize, EFonts font )
|
||||
std::vector<std::string> CMessage::breakText( std::string text, size_t maxLineWidth, EFonts font )
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
|
||||
boost::algorithm::trim_right_if(text,boost::algorithm::is_any_of(std::string(" ")));
|
||||
|
||||
// each interation generates one output line
|
||||
while (text.length())
|
||||
{
|
||||
ui32 lineLength = 0; //in characters or given char metric
|
||||
ui32 wordBreak = -1;
|
||||
ui32 currPos = 0; //our position in text
|
||||
bool opened = false;//if we have an unclosed brace in current line
|
||||
bool lineManuallyBroken = false;
|
||||
ui32 lineWidth = 0; //in characters or given char metric
|
||||
ui32 wordBreak = -1; //last position for line break (last space character)
|
||||
ui32 currPos = 0; //current position in text
|
||||
bool opened = false; //set to true when opening brace is found
|
||||
|
||||
while(currPos < text.length() && text[currPos] != 0x0a && lineLength < maxLineSize)
|
||||
size_t symbolSize = 0; // width of character, in bytes
|
||||
size_t glyphWidth = 0; // width of printable glyph, pixels
|
||||
|
||||
// loops till line is full or end of text reached
|
||||
while(currPos < text.length() && text[currPos] != 0x0a && lineWidth < maxLineWidth)
|
||||
{
|
||||
if (ui8(text[currPos]) <= ui8(' ')) // candidate for line break
|
||||
symbolSize = graphics->fonts[font]->getCharacterSize(text[currPos]);
|
||||
glyphWidth = graphics->fonts[font]->getGlyphWidth(text.data() + currPos);
|
||||
|
||||
// candidate for line break
|
||||
if (ui8(text[currPos]) <= ui8(' '))
|
||||
wordBreak = currPos;
|
||||
|
||||
/* We don't count braces in string length. */
|
||||
if (text[currPos] == '{')
|
||||
opened=true;
|
||||
else if (text[currPos]=='}')
|
||||
opened=false;
|
||||
else
|
||||
lineLength += graphics->fonts[font]->getGlyphWidth(text.data() + currPos);
|
||||
currPos += graphics->fonts[font]->getCharacterSize(text[currPos]);
|
||||
lineWidth += glyphWidth;
|
||||
currPos += symbolSize;
|
||||
}
|
||||
|
||||
// long line, create line break
|
||||
if (currPos < text.length() && (text[currPos] != 0x0a))
|
||||
{
|
||||
// We have a long line. Try to do a nice line break, if possible
|
||||
if (wordBreak != ui32(-1))
|
||||
currPos = wordBreak;
|
||||
else
|
||||
currPos--;
|
||||
currPos -= symbolSize;
|
||||
}
|
||||
|
||||
if(currPos) //non-blank line
|
||||
//non-blank line
|
||||
if(currPos != 0)
|
||||
{
|
||||
ret.push_back(text.substr(0, currPos));
|
||||
|
||||
@@ -176,39 +186,34 @@ std::vector<std::string> CMessage::breakText( std::string text, size_t maxLineSi
|
||||
|
||||
text.erase(0, currPos);
|
||||
}
|
||||
else if(text[currPos] == 0x0a) //blank line
|
||||
else if(text[currPos] == 0x0a)
|
||||
{
|
||||
ret.push_back(""); //add empty string, no extra actions needed
|
||||
}
|
||||
|
||||
if (text.length() && text[0] == 0x0a)
|
||||
if (text.length() != 0 && text[0] == 0x0a)
|
||||
{
|
||||
/* Braces do not carry over lines. The map author forgot
|
||||
* to close it. */
|
||||
opened = false;
|
||||
|
||||
/* Remove LF */
|
||||
text.erase(0, 1);
|
||||
|
||||
lineManuallyBroken = true;
|
||||
}
|
||||
|
||||
//if(!allowLeadingWhitespace || !lineManuallyBroken)
|
||||
if(!lineManuallyBroken)
|
||||
else
|
||||
{
|
||||
// trim only if line does not starts with LF
|
||||
// FIXME: necessary? All lines will be trimmed before returning anyway
|
||||
boost::algorithm::trim_left_if(text,boost::algorithm::is_any_of(std::string(" ")));
|
||||
}
|
||||
|
||||
if (opened)
|
||||
{
|
||||
/* Add an opening brace for the next line. */
|
||||
if (text.length())
|
||||
if (text.length() != 0)
|
||||
text.insert(0, "{");
|
||||
}
|
||||
}
|
||||
|
||||
/* Trim whitespaces of every line. */
|
||||
//if(!allowLeadingWhitespace)
|
||||
for (auto & elem : ret)
|
||||
boost::algorithm::trim(elem);
|
||||
for (auto & elem : ret)
|
||||
boost::algorithm::trim(elem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -332,7 +332,8 @@ static std::function<void()> genCommand(CMenuScreen* menu, std::vector<std::stri
|
||||
case 0: return boost::bind(&CGPreGame::openSel, CGP, CMenuScreen::newGame, CMenuScreen::SINGLE_PLAYER);
|
||||
case 1: return &pushIntT<CMultiMode>;
|
||||
case 2: return boost::bind(&CGPreGame::openSel, CGP, CMenuScreen::campaignList, CMenuScreen::SINGLE_PLAYER);
|
||||
case 3: return std::function<void()>();//TODO: start tutorial
|
||||
//TODO: start tutorial
|
||||
case 3: return boost::bind(CInfoWindow::showInfoDialog, "Sorry, tutorial is not implemented yet\n", (const std::vector<CComponent*>*)nullptr, false, PlayerColor(1));
|
||||
}
|
||||
}
|
||||
break; case 3://load
|
||||
@@ -341,8 +342,10 @@ static std::function<void()> genCommand(CMenuScreen* menu, std::vector<std::stri
|
||||
{
|
||||
case 0: return boost::bind(&CGPreGame::openSel, CGP, CMenuScreen::loadGame, CMenuScreen::SINGLE_PLAYER);
|
||||
case 1: return boost::bind(&CGPreGame::openSel, CGP, CMenuScreen::loadGame, CMenuScreen::MULTI_HOT_SEAT);
|
||||
case 2: return std::function<void()>();//TODO: load campaign
|
||||
case 3: return std::function<void()>();//TODO: load tutorial
|
||||
//TODO: load campaign
|
||||
case 2: return boost::bind(CInfoWindow::showInfoDialog, "This function is not implemented yet. Campaign saves can be loaded from \"Single Player\" menu", (const std::vector<CComponent*>*)nullptr, false, PlayerColor(1));
|
||||
//TODO: load tutorial
|
||||
case 3: return boost::bind(CInfoWindow::showInfoDialog, "Sorry, tutorial is not implemented yet\n", (const std::vector<CComponent*>*)nullptr, false, PlayerColor(1));
|
||||
}
|
||||
}
|
||||
break; case 4://exit
|
||||
@@ -351,7 +354,8 @@ static std::function<void()> genCommand(CMenuScreen* menu, std::vector<std::stri
|
||||
}
|
||||
break; case 5://highscores
|
||||
{
|
||||
return std::function<void()>(); //TODO: high scores &pushIntT<CHighScores>;
|
||||
//TODO: high scores
|
||||
return boost::bind(CInfoWindow::showInfoDialog, "Sorry, high scores menu is not implemented yet\n", (const std::vector<CComponent*>*)nullptr, false, PlayerColor(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -721,6 +721,12 @@ void CInfoWindow::showAll(SDL_Surface * to)
|
||||
CIntObject::showAll(to);
|
||||
}
|
||||
|
||||
void CInfoWindow::showInfoDialog(const std::string &text, const std::vector<CComponent *> *components, bool DelComps, PlayerColor player)
|
||||
{
|
||||
CInfoWindow * window = CInfoWindow::create(text, player, components, DelComps);
|
||||
GH.pushInt(window);
|
||||
}
|
||||
|
||||
void CInfoWindow::showYesNoDialog(const std::string & text, const std::vector<CComponent*> *components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, bool DelComps, PlayerColor player)
|
||||
{
|
||||
assert(!LOCPLINT || LOCPLINT->showingDialog->get());
|
||||
|
@@ -104,7 +104,9 @@ public:
|
||||
CInfoWindow(); //c-tor
|
||||
~CInfoWindow(); //d-tor
|
||||
|
||||
static void showYesNoDialog( const std::string & text, const std::vector<CComponent*> *components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, bool DelComps = true, PlayerColor player = PlayerColor(1)); //use only before the game starts! (showYesNoDialog in LOCPLINT must be used then)
|
||||
//use only before the game starts! (showYesNoDialog in LOCPLINT must be used then)
|
||||
static void showInfoDialog( const std::string & text, const std::vector<CComponent*> *components, bool DelComps = true, PlayerColor player = PlayerColor(1));
|
||||
static void showYesNoDialog( const std::string & text, const std::vector<CComponent*> *components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, bool DelComps = true, PlayerColor player = PlayerColor(1));
|
||||
static CInfoWindow *create(const std::string &text, PlayerColor playerID = PlayerColor(1), const std::vector<CComponent*> *components = nullptr, bool DelComps = false);
|
||||
|
||||
/// create text from title and description: {title}\n\n description
|
||||
|
@@ -365,7 +365,9 @@ void Graphics::addImageListEntry(size_t index, std::string listName, std::string
|
||||
{
|
||||
if (!imageName.empty())
|
||||
{
|
||||
if (!CResourceHandler::get()->existsResource(ResourceID("SPRITES/" + imageName, EResType::IMAGE)))
|
||||
ResourceID resID("SPRITES/" + imageName, EResType::IMAGE);
|
||||
if (!CResourceHandler::get()->existsResource(resID) && // file not found
|
||||
imageName.find(':') == std::string::npos) // and entry does not refers to frame in def file
|
||||
logGlobal->errorStream() << "Required image " << "SPRITES/" << imageName << " is missing!";
|
||||
|
||||
JsonNode entry;
|
||||
|
@@ -353,7 +353,7 @@ void CBitmapHanFont::renderText(SDL_Surface * surface, const std::string & data,
|
||||
for(size_t i=0; i<data.size(); i += getCharacterSize(data[i]))
|
||||
{
|
||||
if (ui8(data[i]) < 0x80)
|
||||
renderCharacter(surface, getCharacterIndex(0xa3, data[i] + 0x80), color, posX, posY);
|
||||
fallback->renderCharacter(surface, fallback->chars[data[i]], color, posX, posY);
|
||||
else
|
||||
renderCharacter(surface, getCharacterIndex(data[i], data[i+1]), color, posX, posY);
|
||||
}
|
||||
@@ -361,6 +361,7 @@ void CBitmapHanFont::renderText(SDL_Surface * surface, const std::string & data,
|
||||
}
|
||||
|
||||
CBitmapHanFont::CBitmapHanFont(const JsonNode &config):
|
||||
fallback(new CBitmapFont(config["fallback"].String())),
|
||||
data(CResourceHandler::get()->load(ResourceID("data/" + config["name"].String(), EResType::OTHER))->readAll()),
|
||||
size(config["size"].Float())
|
||||
{
|
||||
@@ -378,6 +379,8 @@ size_t CBitmapHanFont::getLineHeight() const
|
||||
|
||||
size_t CBitmapHanFont::getGlyphWidth(const char * data) const
|
||||
{
|
||||
if (ui8(data[0]) < 0x80)
|
||||
return fallback->getGlyphWidth(data);
|
||||
return size + 1;
|
||||
}
|
||||
|
||||
|
@@ -97,6 +97,7 @@ public:
|
||||
/// supports multi-byte characters for such languages like Chinese
|
||||
class CBitmapHanFont : public IFont
|
||||
{
|
||||
std::unique_ptr<CBitmapFont> fallback;
|
||||
// data, directly copied from file
|
||||
const std::pair<std::unique_ptr<ui8[]>, ui64> data;
|
||||
|
||||
|
Reference in New Issue
Block a user