1
0
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:
Ivan Savenko
2013-10-20 21:53:27 +00:00
parent 012212698e
commit f6a3d6770f
7 changed files with 58 additions and 35 deletions

View File

@@ -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;
}

View File

@@ -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));
}
}
}

View File

@@ -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());

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;