Skip to content

Commit

Permalink
much better nuiLabel wrapping
Browse files Browse the repository at this point in the history
added wrapping, justification, left, right and center text layout implementations
  • Loading branch information
meeloo committed Apr 9, 2014
1 parent da4799f commit e7273ca
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 33 deletions.
1 change: 1 addition & 0 deletions include/nuiTextLayout.h
Expand Up @@ -109,6 +109,7 @@ class nuiTextLayout : public nuiRefCount

float mSpaceWidth = 0;
float mTabWidth = 0;
float mWrapX = 0;

};

3 changes: 3 additions & 0 deletions include/nuiTextLine.h
Expand Up @@ -34,6 +34,9 @@ class nuiTextLine

const nuiTextGlyph* GetGlyph (int32 Offset) const;
const nuiTextGlyph* GetGlyphAt (float X, float Y) const;

float PreLayout(float wrap);
float Layout(float X, float Y, float width, nuiTextLayoutMode mode, nuiRect& globalrect);
private:
friend class nuiTextLayout;

Expand Down
3 changes: 3 additions & 0 deletions include/nuiTextRun.h
Expand Up @@ -86,6 +86,8 @@ class nuiTextRun : public nuiRefCount
nuiRect GetRect() const;

bool IsDummy() const;
bool IsWrapStart() const;
void SetWrapStart(bool set);

const nuiTextStyle& GetStyle() const;

Expand All @@ -101,6 +103,7 @@ class nuiTextRun : public nuiRefCount
bool mUnderline : 1;
bool mStrikeThrough : 1;
bool mDummy : 1;
bool mWrapStart : 1;

std::vector<nuiTextGlyph> mGlyphs;
float mX;
Expand Down
14 changes: 11 additions & 3 deletions include/nuiTextStyle.h
Expand Up @@ -24,6 +24,14 @@ enum nuiTextBaseline
nuiTextBaselineSubScript
};

enum nuiTextLayoutMode
{
nuiTextLayoutJustify,
nuiTextLayoutCenter,
nuiTextLayoutLeft,
nuiTextLayoutRight
};

class nuiTextStyle
{
public:
Expand Down Expand Up @@ -52,8 +60,8 @@ class nuiTextStyle
nuiTextBaseline GetBaseline() const;
void SetDirection(nuiTextDirection set);
nuiTextDirection GetDirection() const;
void SetJustify(bool set);
bool GetJustify() const;
void SetMode(nuiTextLayoutMode set);
nuiTextLayoutMode GetMode() const;

private:
nuiFontBase* mpFont;
Expand All @@ -65,7 +73,7 @@ class nuiTextStyle
bool mUnderline : 1;
bool mStrikeThrough : 1;
nuiTextBaseline mBaseline;
bool mJustify : 1;
nuiTextLayoutMode mMode;
nuiTextDirection mDirection;
};

65 changes: 44 additions & 21 deletions src/Font/nuiTextLayout.cpp
Expand Up @@ -153,7 +153,8 @@ bool nuiTextLayout::Layout(const nglString& rString)
nuiRect rect;
float PenX = 0;
float PenY = 0;
// Assign the correct font to each run
float maxwidth = 0;
// First pass: Assign the correct font to each run, shape the runs and calculate wraping if needed:
for (uint32 p = 0; p < mpParagraphs.size(); p++)
{
Paragraph* pParagraph = mpParagraphs[p];
Expand Down Expand Up @@ -182,28 +183,33 @@ bool nuiTextLayout::Layout(const nglString& rString)

nuiFontInfo finfo;
pFont->GetInfo(finfo);


// Prepare glyphs:

std::vector<nuiTextGlyph>& rGlyphs(pRun->GetGlyphs());
for (int32 g = 0; g < rGlyphs.size(); g++)

if (mWrapX > 0)
{
nuiTextGlyph& rGlyph(rGlyphs.at(g));

pFont->PrepareGlyph(PenX + x, PenY + y, rGlyph);

const nuiSize W = rGlyph.AdvanceX;
// nuiSize h = finfo.AdvanceMaxH;
const nuiSize X = rGlyph.mX + rGlyph.BearingX;
const nuiSize Y = rGlyph.mY - finfo.Ascender;
const nuiSize H = finfo.Height;

nuiRect rr(rect);
rect.Union(rr, nuiRect(PenX + x + X, PenY + y + Y, W, H));
// compute the bounding box:
float runw = 0;
for (int32 g = 0; g < rGlyphs.size(); g++)
{
const nuiTextGlyph& rGlyph(rGlyphs.at(g));
runw += rGlyph.AdvanceX;
}

if (PenX + x + runw >= mWrapX)
{
PenX = 0;
x = 0;
y += finfo.Height;
pRun->SetWrapStart(true);
}
}

}

x += pRun->GetAdvanceX();
maxwidth = MAX(maxwidth, PenX + x);

//y += pRun->GetAdvanceY();


Expand All @@ -214,7 +220,24 @@ bool nuiTextLayout::Layout(const nglString& rString)
PenY += pLine->GetAdvanceY();
}
}


PenX = 0;
PenY = 0;

// Now place the glyphs correctly
for (uint32 p = 0; p < mpParagraphs.size(); p++)
{
Paragraph* pParagraph = mpParagraphs[p];
for (uint32 l = 0; l < pParagraph->size(); l++)
{
nuiTextLine* pLine = (*pParagraph)[l];

PenY = pLine->Layout(PenX, PenY, maxwidth, nuiTextLayoutCenter, rect);
//PenY += pLine->GetAdvanceY();
}
}


nuiTextLine* pFirstLine = NULL;
if (GetParagraphCount() > 0)
if (GetLineCount(0) > 0)
Expand Down Expand Up @@ -524,12 +547,12 @@ nuiRect nuiTextLayout::GetRect() const

void nuiTextLayout::SetWrapX(nuiSize WrapX)
{

mWrapX = WrapX;
}

nuiSize nuiTextLayout::GetWrapX() const
{
return 0;
return mWrapX;
}


Expand Down
179 changes: 179 additions & 0 deletions src/Font/nuiTextLine.cpp
Expand Up @@ -139,4 +139,183 @@ const nuiTextGlyph* nuiTextLine::GetGlyphAt(float X, float Y) const
return NULL;
}

float LayoutDirect(float PenX, float PenY, float globalwidth, float sublinewidth, float spacewidth, std::list<nuiTextRun*>& subline, nuiRect& globalrect)
{
float h = 0;
float x = 0;
float y = 0;
for (nuiTextRun* pRun : subline)
{
nuiFontBase* pFont = pRun->GetFont();

nuiFontInfo finfo;

if (pFont)
pFont->GetInfo(finfo);

std::vector<nuiTextGlyph>& rGlyphs(pRun->GetGlyphs());

// Prepare glyphs:
for (int32 g = 0; g < rGlyphs.size(); g++)
{
nuiTextGlyph& rGlyph(rGlyphs.at(g));

pFont->PrepareGlyph(PenX + x, PenY + y, rGlyph);

const nuiSize W = rGlyph.AdvanceX;
const nuiSize X = rGlyph.mX + rGlyph.BearingX;
const nuiSize Y = rGlyph.mY - finfo.Ascender;
const nuiSize H = finfo.Height;

h = MAX(h, H);
nuiRect rr(globalrect);
globalrect.Union(rr, nuiRect(PenX + x + X, PenY + y + Y, W, H));
}

x += pRun->GetAdvanceX();
}

return h;
}

float LayoutJustify(float PenX, float PenY, float globalwidth, float sublinewidth, float spacewidth, std::list<nuiTextRun*>& subline, nuiRect& globalrect)
{
float h = 0;
float x = 0;
float y = 0;

float ratio = (globalwidth - (sublinewidth - spacewidth)) / spacewidth;
for (nuiTextRun* pRun : subline)
{
nuiFontBase* pFont = pRun->GetFont();

nuiFontInfo finfo;
pFont->GetInfo(finfo);

std::vector<nuiTextGlyph>& rGlyphs(pRun->GetGlyphs());

// Prepare glyphs:
for (int32 g = 0; g < rGlyphs.size(); g++)
{
nuiTextGlyph& rGlyph(rGlyphs.at(g));

pFont->PrepareGlyph(PenX + x, PenY + y, rGlyph);

const nuiSize W = rGlyph.AdvanceX;
const nuiSize X = rGlyph.mX + rGlyph.BearingX;
const nuiSize Y = rGlyph.mY - finfo.Ascender;
const nuiSize H = finfo.Height;

h = MAX(h, H);
nuiRect rr(globalrect);
globalrect.Union(rr, nuiRect(PenX + x + X, PenY + y + Y, W, H));
}

if (pRun->IsDummy())
{
x += pRun->GetAdvanceX() * ratio;
}
else
{
x += pRun->GetAdvanceX();
}
}

return h;
}


float LayoutLeft(float PenX, float PenY, float globalwidth, float sublinewidth, float spacewidth, std::list<nuiTextRun*>& subline, nuiRect& globalrect)
{
return LayoutDirect(PenX, PenY, globalwidth, sublinewidth, spacewidth, subline, globalrect);
}


float LayoutRight(float PenX, float PenY, float globalwidth, float sublinewidth, float spacewidth, std::list<nuiTextRun*>& subline, nuiRect& globalrect)
{
float x = globalwidth - sublinewidth;
return LayoutDirect(PenX + x, PenY, globalwidth, sublinewidth, spacewidth, subline, globalrect);
}

float LayoutCenter(float PenX, float PenY, float globalwidth, float sublinewidth, float spacewidth, std::list<nuiTextRun*>& subline, nuiRect& globalrect)
{
float x = (globalwidth - sublinewidth) / 2;
return LayoutDirect(PenX + x, PenY, globalwidth, sublinewidth, spacewidth, subline, globalrect);
}



float nuiTextLine::Layout(float PenX, float PenY, float width, nuiTextLayoutMode mode, nuiRect& globalrect)
{
SetPosition(PenX, PenY);

PenX = 0;
float x = 0;
float y = 0;

std::vector< std::list <nuiTextRun*> > sublines;
sublines.resize(1);
bool sublinestart = true;
// Prepare sublines:
for (uint32 r = 0; r < GetRunCount(); r++)
{
nuiTextRun* pRun = GetRun(r);
if (pRun->IsWrapStart())
sublines.resize(sublines.size() + 1);

sublines.back().push_back(pRun);
}

// Trim the dummy runs:
for (int l = 1; l < sublines.size(); l++)
{
// Remove dummy text runs from the start of the lines (except the first line):
while (!sublines.empty() && sublines[l].front()->IsDummy())
sublines[l].pop_front();

// Remove dummy text runs from the end of the lines:
while (!sublines.empty() && sublines[l].back()->IsDummy())
sublines[l].pop_back();
}


// Now position each run inside each subline:
for (int l = 0; l < sublines.size(); l++)
{
float w = 0;
float space = 0;
for (nuiTextRun* pRun : sublines[l])
{
float a = pRun->GetAdvanceX();
w += a;
if (pRun->IsDummy())
space += a;
}

float h = 0;
switch (mode)
{
case nuiTextLayoutLeft:
h = LayoutLeft(PenX, PenY, width, w, space, sublines[l], globalrect);
break;

case nuiTextLayoutRight:
h = LayoutRight(PenX, PenY, width, w, space, sublines[l], globalrect);
break;

case nuiTextLayoutJustify:
h = LayoutJustify(PenX, PenY, width, w, space, sublines[l], globalrect);
break;

case nuiTextLayoutCenter:
h = LayoutCenter(PenX, PenY, width, w, space, sublines[l], globalrect);
break;
}

PenY += h;
}

return PenY;
}


15 changes: 14 additions & 1 deletion src/Font/nuiTextRun.cpp
Expand Up @@ -20,6 +20,7 @@ nuiTextRun::nuiTextRun(const nuiTextLayout& rLayout, nuiUnicodeScript script, in
mUnderline(false),
mStrikeThrough(false),
mDummy(false),
mWrapStart(false),
mStyle(rStyle)
{
}
Expand All @@ -35,7 +36,8 @@ nuiTextRun::nuiTextRun(const nuiTextLayout& rLayout, int32 Position, int32 Lengt
mAdvanceY(AdvanceY),
mUnderline(false),
mStrikeThrough(false),
mDummy(true)
mDummy(true),
mWrapStart(false)
{
}

Expand Down Expand Up @@ -186,3 +188,14 @@ const nuiTextStyle& nuiTextRun::GetStyle() const
return mStyle;
}

bool nuiTextRun::IsWrapStart() const
{
return mWrapStart;
}

void nuiTextRun::SetWrapStart(bool set)
{
mWrapStart = set;
}


0 comments on commit e7273ca

Please sign in to comment.