Added proper text alignment to the Font class.

Multiline text is now centered/right-aligned correctly.
This commit is contained in:
Aloshi 2014-05-12 20:03:02 -05:00
parent 4cf206d3eb
commit 5d0df7acf8
4 changed files with 62 additions and 51 deletions

View file

@ -82,22 +82,7 @@ void TextComponent::render(const Eigen::Affine3f& parentTrans)
if(mTextCache) if(mTextCache)
{ {
const Eigen::Vector2f& textSize = mTextCache->metrics.size; const Eigen::Vector2f& textSize = mTextCache->metrics.size;
Eigen::Vector3f off(0, 0, 0); Eigen::Vector3f off(0, (getSize().y() - textSize.y()) / 2.0f, 0);
switch(mAlignment)
{
case ALIGN_LEFT:
off << 0, (getSize().y() - textSize.y()) / 2, 0;
break;
case ALIGN_CENTER:
off << (getSize().x() - textSize.x()) / 2, (getSize().y() - textSize.y()) / 2, 0;
break;
case ALIGN_RIGHT:
off << (getSize().x() - textSize.x()), (getSize().y() - textSize.y()) / 2, 0;
break;
}
if(Settings::getInstance()->getBool("DebugText")) if(Settings::getInstance()->getBool("DebugText"))
{ {
@ -112,7 +97,20 @@ void TextComponent::render(const Eigen::Affine3f& parentTrans)
// draw the text area, where the text actually is going // draw the text area, where the text actually is going
if(Settings::getInstance()->getBool("DebugText")) if(Settings::getInstance()->getBool("DebugText"))
{
switch(mAlignment)
{
case ALIGN_LEFT:
Renderer::drawRect(0.0f, 0.0f, mTextCache->metrics.size.x(), mTextCache->metrics.size.y(), 0x00000033); Renderer::drawRect(0.0f, 0.0f, mTextCache->metrics.size.x(), mTextCache->metrics.size.y(), 0x00000033);
break;
case ALIGN_CENTER:
Renderer::drawRect((mSize.x() - mTextCache->metrics.size.x()) / 2.0f, 0.0f, mTextCache->metrics.size.x(), mTextCache->metrics.size.y(), 0x00000033);
break;
case ALIGN_RIGHT:
Renderer::drawRect(mSize.x() - mTextCache->metrics.size.x(), 0.0f, mTextCache->metrics.size.x(), mTextCache->metrics.size.y(), 0x00000033);
break;
}
}
mFont->renderTextCache(mTextCache.get()); mFont->renderTextCache(mTextCache.get());
} }
@ -140,7 +138,7 @@ void TextComponent::onTextChanged()
std::string text = mUppercase ? strToUpper(mText) : mText; std::string text = mUppercase ? strToUpper(mText) : mText;
std::shared_ptr<Font> f = getFont(); std::shared_ptr<Font> f = getFont();
const bool wrap = (mSize.y() == 0 || (int)mSize.y() > f->getHeight()); const bool wrap = (mSize.y() == 0 || mSize.y() > f->getHeight()*1.2f);
Eigen::Vector2f size = f->sizeText(text); Eigen::Vector2f size = f->sizeText(text);
if(!wrap && mSize.x() && text.size() && size.x() > mSize.x()) if(!wrap && mSize.x() && text.size() && size.x() > mSize.x())
{ {
@ -156,9 +154,9 @@ void TextComponent::onTextChanged()
text.append(abbrev); text.append(abbrev);
mTextCache = std::shared_ptr<TextCache>(f->buildTextCache(text, 0, 0, (mColor >> 8 << 8) | mOpacity)); mTextCache = std::shared_ptr<TextCache>(f->buildTextCache(text, Eigen::Vector2f(0, 0), (mColor >> 8 << 8) | mOpacity, mSize.x(), mAlignment));
}else{ }else{
mTextCache = std::shared_ptr<TextCache>(f->buildTextCache(f->wrapText(text, mSize.x()), 0, 0, (mColor >> 8 << 8) | mOpacity)); mTextCache = std::shared_ptr<TextCache>(f->buildTextCache(f->wrapText(text, mSize.x()), Eigen::Vector2f(0, 0), (mColor >> 8 << 8) | mOpacity, mSize.x(), mAlignment));
} }
} }

View file

@ -386,6 +386,27 @@ Eigen::Vector2f Font::getWrappedTextCursorOffset(std::string text, float xLen, i
//TextCache //TextCache
//============================================================================================================= //=============================================================================================================
float Font::getNewlineStartOffset(const std::string& text, const unsigned int& charStart, const float& xLen, const Alignment& alignment)
{
switch(alignment)
{
case ALIGN_LEFT:
return 0;
case ALIGN_CENTER:
{
unsigned int endChar = text.find('\n', charStart);
return (xLen - sizeText(text.substr(charStart, endChar != std::string::npos ? endChar - charStart : endChar)).x()) / 2.0f;
}
case ALIGN_RIGHT:
{
unsigned int endChar = text.find('\n', charStart);
return xLen - (sizeText(text.substr(charStart, endChar != std::string::npos ? endChar - charStart : endChar)).x());
}
default:
return 0;
}
}
TextCache* Font::buildTextCache(const std::string& text, Eigen::Vector2f offset, unsigned int color, float xLen, Alignment alignment, float lineSpacing) TextCache* Font::buildTextCache(const std::string& text, Eigen::Vector2f offset, unsigned int color, float xLen, Alignment alignment, float lineSpacing)
{ {
if(!mTextureID) if(!mTextureID)
@ -394,50 +415,28 @@ TextCache* Font::buildTextCache(const std::string& text, Eigen::Vector2f offset,
return NULL; return NULL;
} }
// todo const unsigned int vertCount = text.length() * 2 * 3; // 2 triangles of 3 vertices per character
return NULL;
}
TextCache* Font::buildTextCache(const std::string& text, float offsetX, float offsetY, unsigned int color)
{
if(!mTextureID)
{
LOG(LogError) << "Error - tried to build TextCache with Font that has no texture loaded!";
return NULL;
}
const int triCount = text.length() * 2;
const int vertCount = triCount * 3;
TextCache::Vertex* vert = new TextCache::Vertex[vertCount]; TextCache::Vertex* vert = new TextCache::Vertex[vertCount];
GLubyte* colors = new GLubyte[vertCount * 4]; GLubyte* colors = new GLubyte[vertCount * 4];
// all glyph sizes/texture offsets are in pixels,
// so the only rounding we have to worry about is the offset
offsetX = round(offsetX);
offsetY = round(offsetY);
//texture atlas width/height //texture atlas width/height
float tw = (float)mTextureWidth; float tw = (float)mTextureWidth;
float th = (float)mTextureHeight; float th = (float)mTextureHeight;
float x = offsetX; float x = offset[0] + (xLen != 0 ? getNewlineStartOffset(text, 0, xLen, alignment) : 0);
float yTop = mCharData['S'].bearingY * mFontScale; float yTop = mCharData['S'].bearingY * mFontScale;
float yBot = getHeight(); float yBot = getHeight(lineSpacing);
float y = offsetY + (yBot + yTop)/2.0f; float y = offset[1] + (yBot + yTop)/2.0f;
int charNum = 0; for(unsigned int i = 0, charNum = 0; i < vertCount; i += 6, charNum++)
for(int i = 0; i < vertCount; i += 6, charNum++)
{ {
unsigned char letter = text[charNum]; unsigned char letter = text[charNum];
if(letter == '\n') if(letter == '\n')
{ {
y += (float)getHeight(); y += getHeight(lineSpacing);
x = offsetX; x = offset[0] + (xLen != 0 ? getNewlineStartOffset(text, charNum+1, xLen, alignment) : 0);
memset(&vert[i], 0, 6 * sizeof(TextCache::Vertex)); memset(&vert[i], 0, 6 * sizeof(TextCache::Vertex));
continue; continue;
} }
@ -470,6 +469,13 @@ TextCache* Font::buildTextCache(const std::string& text, float offsetX, float of
vert[i + 5].tex[0] = vert[i + 1].tex.x(); vert[i + 5].tex[0] = vert[i + 1].tex.x();
vert[i + 5].tex[1] = vert[i + 0].tex.y(); vert[i + 5].tex[1] = vert[i + 0].tex.y();
// round to fix some weird "cut off" text bugs
for(unsigned int j = i; j < i + 6; j++)
{
vert[j].pos[0] = round(vert[j].pos[0]);
vert[j].pos[1] = round(vert[j].pos[1]);
}
x += mCharData[letter].advX * mFontScale; x += mCharData[letter].advX * mFontScale;
} }
@ -481,6 +487,11 @@ TextCache* Font::buildTextCache(const std::string& text, float offsetX, float of
return cache; return cache;
} }
TextCache* Font::buildTextCache(const std::string& text, float offsetX, float offsetY, unsigned int color)
{
return buildTextCache(text, Eigen::Vector2f(offsetX, offsetY), color, 0.0f);
}
TextCache::TextCache(int verts, Vertex* v, GLubyte* c, const CacheMetrics& m) : vertCount(verts), verts(v), colors(c), metrics(m) TextCache::TextCache(int verts, Vertex* v, GLubyte* c, const CacheMetrics& m) : vertCount(verts), verts(v), colors(c), metrics(m)
{ {
} }

View file

@ -99,6 +99,8 @@ private:
int mSize; int mSize;
const std::string mPath; const std::string mPath;
float getNewlineStartOffset(const std::string& text, const unsigned int& charStart, const float& xLen, const Alignment& alignment);
friend TextCache; friend TextCache;
}; };

View file

@ -107,7 +107,7 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& them
mDescContainer.applyTheme(theme, getName(), "md_description", POSITION | ThemeFlags::SIZE); mDescContainer.applyTheme(theme, getName(), "md_description", POSITION | ThemeFlags::SIZE);
mDescription.setSize(mDescContainer.getSize().x(), 0); mDescription.setSize(mDescContainer.getSize().x(), 0);
mDescription.applyTheme(theme, getName(), "md_description", FONT_PATH | FONT_SIZE | COLOR | FORCE_UPPERCASE); mDescription.applyTheme(theme, getName(), "md_description", FONT_PATH | FONT_SIZE | COLOR | FORCE_UPPERCASE | ALIGNMENT);
} }
void DetailedGameListView::initMDLabels() void DetailedGameListView::initMDLabels()