1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Modified TextLayout creation functions to take an optional maximum height as well as a maximum width.

This commit is contained in:
jules 2014-12-29 12:07:31 +00:00
parent 04cb9bf3e8
commit a49baa3e52
3 changed files with 121 additions and 75 deletions

View file

@ -22,8 +22,8 @@
==============================================================================
*/
TextLayout::Glyph::Glyph (const int glyphCode_, Point<float> anchor_, float width_) noexcept
: glyphCode (glyphCode_), anchor (anchor_), width (width_)
TextLayout::Glyph::Glyph (const int glyph, Point<float> anch, float w) noexcept
: glyphCode (glyph), anchor (anch), width (w)
{
}
@ -70,11 +70,10 @@ TextLayout::Line::Line() noexcept
{
}
TextLayout::Line::Line (Range<int> stringRange_, Point<float> lineOrigin_,
const float ascent_, const float descent_, const float leading_,
const int numRunsToPreallocate)
: stringRange (stringRange_), lineOrigin (lineOrigin_),
ascent (ascent_), descent (descent_), leading (leading_)
TextLayout::Line::Line (Range<int> range, Point<float> o, float asc, float desc,
float lead, int numRunsToPreallocate)
: stringRange (range), lineOrigin (o),
ascent (asc), descent (desc), leading (lead)
{
runs.ensureStorageAllocated (numRunsToPreallocate);
}
@ -127,14 +126,28 @@ Range<float> TextLayout::Line::getLineBoundsX() const noexcept
return range + lineOrigin.x;
}
Range<float> TextLayout::Line::getLineBoundsY() const noexcept
{
return Range<float> (lineOrigin.y - ascent,
lineOrigin.y + descent);
}
Rectangle<float> TextLayout::Line::getLineBounds() const noexcept
{
const Range<float> x (getLineBoundsX()),
y (getLineBoundsY());
return Rectangle<float> (x.getStart(), y.getStart(), x.getLength(), y.getLength());
}
//==============================================================================
TextLayout::TextLayout()
: width (0), justification (Justification::topLeft)
: width (0), height (0), justification (Justification::topLeft)
{
}
TextLayout::TextLayout (const TextLayout& other)
: width (other.width),
: width (other.width), height (other.height),
justification (other.justification)
{
lines.addCopiesOf (other.lines);
@ -142,16 +155,17 @@ TextLayout::TextLayout (const TextLayout& other)
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
TextLayout::TextLayout (TextLayout&& other) noexcept
: lines (static_cast <OwnedArray<Line>&&> (other.lines)),
width (other.width),
: lines (static_cast<OwnedArray<Line>&&> (other.lines)),
width (other.width), height (other.height),
justification (other.justification)
{
}
TextLayout& TextLayout::operator= (TextLayout&& other) noexcept
{
lines = static_cast <OwnedArray<Line>&&> (other.lines);
lines = static_cast<OwnedArray<Line>&&> (other.lines);
width = other.width;
height = other.height;
justification = other.justification;
return *this;
}
@ -160,6 +174,7 @@ TextLayout& TextLayout::operator= (TextLayout&& other) noexcept
TextLayout& TextLayout::operator= (const TextLayout& other)
{
width = other.width;
height = other.height;
justification = other.justification;
lines.clear();
lines.addCopiesOf (other.lines);
@ -170,17 +185,9 @@ TextLayout::~TextLayout()
{
}
float TextLayout::getHeight() const noexcept
{
if (const Line* const lastLine = lines.getLast())
return lastLine->lineOrigin.y + lastLine->descent;
return 0.0f;
}
TextLayout::Line& TextLayout::getLine (const int index) const
{
return *lines[index];
return *lines.getUnchecked (index);
}
void TextLayout::ensureStorageAllocated (int numLinesNeeded)
@ -199,7 +206,7 @@ void TextLayout::draw (Graphics& g, const Rectangle<float>& area) const
LowLevelGraphicsContext& context = g.getInternalContext();
for (int i = 0; i < getNumLines(); ++i)
for (int i = 0; i < lines.size(); ++i)
{
const Line& line = getLine (i);
const Point<float> lineOrigin (origin + line.lineOrigin);
@ -221,15 +228,60 @@ void TextLayout::draw (Graphics& g, const Rectangle<float>& area) const
}
void TextLayout::createLayout (const AttributedString& text, float maxWidth)
{
createLayout (text, maxWidth, 1.0e7f);
}
void TextLayout::createLayout (const AttributedString& text, float maxWidth, float maxHeight)
{
lines.clear();
width = maxWidth;
height = maxHeight;
justification = text.getJustification();
if (! createNativeLayout (text))
createStandardLayout (text);
recalculateWidth (text);
recalculateSize (text);
}
void TextLayout::createLayoutWithBalancedLineLengths (const AttributedString& text, float maxWidth)
{
createLayoutWithBalancedLineLengths (text, maxWidth, 1.0e7f);
}
void TextLayout::createLayoutWithBalancedLineLengths (const AttributedString& text, float maxWidth, float maxHeight)
{
const float minimumWidth = maxWidth / 2.0f;
float bestWidth = maxWidth;
float bestLineProportion = 0.0f;
while (maxWidth > minimumWidth)
{
createLayout (text, maxWidth, maxHeight);
if (getNumLines() < 2)
return;
const float line1 = lines.getUnchecked (lines.size() - 1)->getLineBoundsX().getLength();
const float line2 = lines.getUnchecked (lines.size() - 2)->getLineBoundsX().getLength();
const float shortestLine = jmin (line1, line2);
const float prop = (shortestLine > 0) ? jmax (line1, line2) / shortestLine : 1.0f;
if (prop > 0.9f)
return;
if (prop > bestLineProportion)
{
bestLineProportion = prop;
bestWidth = maxWidth;
}
maxWidth -= 10.0f;
}
if (bestWidth != maxWidth)
createLayout (text, bestWidth, maxHeight);
}
//==============================================================================
@ -305,8 +357,8 @@ namespace TextLayoutHelpers
{
const Token& t = *tokens.getUnchecked (i);
Array <int> newGlyphs;
Array <float> xOffsets;
Array<int> newGlyphs;
Array<float> xOffsets;
t.font.getGlyphPositions (getTrimmedEndIfNotAllWhitespace (t.text), newGlyphs, xOffsets);
if (currentRun == nullptr) currentRun = new TextLayout::Run();
@ -561,41 +613,6 @@ namespace TextLayoutHelpers
};
}
//==============================================================================
void TextLayout::createLayoutWithBalancedLineLengths (const AttributedString& text, float maxWidth)
{
const float minimumWidth = maxWidth / 2.0f;
float bestWidth = maxWidth;
float bestLineProportion = 0.0f;
while (maxWidth > minimumWidth)
{
createLayout (text, maxWidth);
if (getNumLines() < 2)
return;
const float line1 = lines.getUnchecked (lines.size() - 1)->getLineBoundsX().getLength();
const float line2 = lines.getUnchecked (lines.size() - 2)->getLineBoundsX().getLength();
const float shortestLine = jmin (line1, line2);
const float prop = (shortestLine > 0) ? jmax (line1, line2) / shortestLine : 1.0f;
if (prop > 0.9f)
return;
if (prop > bestLineProportion)
{
bestLineProportion = prop;
bestWidth = maxWidth;
}
maxWidth -= 10.0f;
}
if (bestWidth != maxWidth)
createLayout (text, bestWidth);
}
//==============================================================================
void TextLayout::createStandardLayout (const AttributedString& text)
{
@ -603,18 +620,19 @@ void TextLayout::createStandardLayout (const AttributedString& text)
l.createLayout (text, *this);
}
void TextLayout::recalculateWidth (const AttributedString& text)
void TextLayout::recalculateSize (const AttributedString& text)
{
if (lines.size() > 0 && text.getReadingDirection() != AttributedString::rightToLeft)
{
Range<float> range (lines.getFirst()->getLineBoundsX());
Rectangle<float> bounds (lines.getFirst()->getLineBounds());
for (int i = lines.size(); --i > 0;)
range = range.getUnionWith (lines.getUnchecked(i)->getLineBoundsX());
bounds = bounds.getUnion (lines.getUnchecked(i)->getLineBounds());
for (int i = lines.size(); --i >= 0;)
lines.getUnchecked(i)->lineOrigin.x -= range.getStart();
lines.getUnchecked(i)->lineOrigin.x -= bounds.getX();
width = range.getLength();
width = bounds.getWidth();
height = bounds.getHeight();
}
}