@@ -254,7 +254,7 @@ | |||||
actually show it to the user in a list (why??)... Anyway, this macro lets you | actually show it to the user in a list (why??)... Anyway, this macro lets you | ||||
provide a sensible name for that class to make it clear what plugin it refers to. | provide a sensible name for that class to make it clear what plugin it refers to. | ||||
Obviously this has to be a valid obj-C class name. | Obviously this has to be a valid obj-C class name. | ||||
Just to make things a little more complicated, this name must also be unique to this | Just to make things a little more complicated, this name must also be unique to this | ||||
precise version of your software. Otherwise, if the host loads two plugins that use the | precise version of your software. Otherwise, if the host loads two plugins that use the | ||||
same class name, the obj-C linker will almost certainly connect the wrong modules together | same class name, the obj-C linker will almost certainly connect the wrong modules together | ||||
@@ -553,7 +553,6 @@ | |||||
}; | }; | ||||
C0E91ACA08A95435008D54AB /* Debug */ = { | C0E91ACA08A95435008D54AB /* Debug */ = { | ||||
isa = XCBuildConfiguration; | isa = XCBuildConfiguration; | ||||
baseConfigurationReference = 846929130A49DB9C00314975 /* juce.xcconfig */; | |||||
buildSettings = { | buildSettings = { | ||||
GCC_VERSION = 4.0; | GCC_VERSION = 4.0; | ||||
GCC_WARN_ABOUT_RETURN_TYPE = YES; | GCC_WARN_ABOUT_RETURN_TYPE = YES; | ||||
@@ -565,7 +564,6 @@ | |||||
}; | }; | ||||
C0E91ACB08A95435008D54AB /* Release */ = { | C0E91ACB08A95435008D54AB /* Release */ = { | ||||
isa = XCBuildConfiguration; | isa = XCBuildConfiguration; | ||||
baseConfigurationReference = 846929130A49DB9C00314975 /* juce.xcconfig */; | |||||
buildSettings = { | buildSettings = { | ||||
GCC_VERSION = 4.0; | GCC_VERSION = 4.0; | ||||
GCC_WARN_ABOUT_RETURN_TYPE = YES; | GCC_WARN_ABOUT_RETURN_TYPE = YES; | ||||
@@ -86677,7 +86677,7 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, | |||||
{ | { | ||||
// curtail the string if it's too wide.. | // curtail the string if it's too wide.. | ||||
if (useEllipsis && textLen > 3 && glyphs.size() >= 3) | if (useEllipsis && textLen > 3 && glyphs.size() >= 3) | ||||
appendEllipsis (font, xOffset + maxWidthPixels); | |||||
insertEllipsis (font, xOffset + maxWidthPixels, 0, glyphs.size()); | |||||
break; | break; | ||||
} | } | ||||
@@ -86697,8 +86697,11 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, | |||||
} | } | ||||
} | } | ||||
void GlyphArrangement::appendEllipsis (const Font& font, const float maxXPixels) throw() | |||||
int GlyphArrangement::insertEllipsis (const Font& font, const float maxXPos, | |||||
const int startIndex, int endIndex) throw() | |||||
{ | { | ||||
int numDeleted = 0; | |||||
if (glyphs.size() > 0) | if (glyphs.size() > 0) | ||||
{ | { | ||||
Array<int> dotGlyphs; | Array<int> dotGlyphs; | ||||
@@ -86708,15 +86711,16 @@ void GlyphArrangement::appendEllipsis (const Font& font, const float maxXPixels) | |||||
const float dx = dotXs[1]; | const float dx = dotXs[1]; | ||||
float xOffset = 0.0f, yOffset = 0.0f; | float xOffset = 0.0f, yOffset = 0.0f; | ||||
for (int dotPos = 3; --dotPos >= 0 && glyphs.size() > 0;) | |||||
while (endIndex > startIndex) | |||||
{ | { | ||||
const PositionedGlyph* pg = glyphs.getUnchecked (glyphs.size() - 1); | |||||
const PositionedGlyph* pg = glyphs.getUnchecked (--endIndex); | |||||
xOffset = pg->x; | xOffset = pg->x; | ||||
yOffset = pg->y; | yOffset = pg->y; | ||||
glyphs.removeLast(); | |||||
glyphs.remove (endIndex); | |||||
++numDeleted; | |||||
if (xOffset + dx * 3 <= maxXPixels) | |||||
if (xOffset + dx * 3 <= maxXPos) | |||||
break; | break; | ||||
} | } | ||||
@@ -86729,11 +86733,17 @@ void GlyphArrangement::appendEllipsis (const Font& font, const float maxXPixels) | |||||
pg->font = font; | pg->font = font; | ||||
pg->character = '.'; | pg->character = '.'; | ||||
pg->glyph = dotGlyphs.getFirst(); | pg->glyph = dotGlyphs.getFirst(); | ||||
glyphs.add (pg); | |||||
glyphs.insert (endIndex++, pg); | |||||
--numDeleted; | |||||
xOffset += dx; | xOffset += dx; | ||||
if (xOffset > maxXPos) | |||||
break; | |||||
} | } | ||||
} | } | ||||
return numDeleted; | |||||
} | } | ||||
void GlyphArrangement::addJustifiedText (const Font& font, | void GlyphArrangement::addJustifiedText (const Font& font, | ||||
@@ -86820,8 +86830,8 @@ void GlyphArrangement::addJustifiedText (const Font& font, | |||||
void GlyphArrangement::addFittedText (const Font& f, | void GlyphArrangement::addFittedText (const Font& f, | ||||
const String& text, | const String& text, | ||||
float x, float y, | |||||
float width, float height, | |||||
const float x, const float y, | |||||
const float width, const float height, | |||||
const Justification& layout, | const Justification& layout, | ||||
int maximumLines, | int maximumLines, | ||||
const float minimumHorizontalScale) throw() | const float minimumHorizontalScale) throw() | ||||
@@ -86869,37 +86879,24 @@ void GlyphArrangement::addFittedText (const Font& f, | |||||
if (lineWidth * minimumHorizontalScale < width) | if (lineWidth * minimumHorizontalScale < width) | ||||
{ | { | ||||
if (lineWidth > width) | if (lineWidth > width) | ||||
{ | |||||
stretchRangeOfGlyphs (startIndex, glyphs.size() - startIndex, | stretchRangeOfGlyphs (startIndex, glyphs.size() - startIndex, | ||||
width / lineWidth); | width / lineWidth); | ||||
} | |||||
justifyGlyphs (startIndex, glyphs.size() - startIndex, | justifyGlyphs (startIndex, glyphs.size() - startIndex, | ||||
x, y, width, height, layout); | x, y, width, height, layout); | ||||
} | } | ||||
else if (maximumLines <= 1) | else if (maximumLines <= 1) | ||||
{ | { | ||||
const float ratio = jmax (minimumHorizontalScale, width / lineWidth); | |||||
stretchRangeOfGlyphs (startIndex, glyphs.size() - startIndex, ratio); | |||||
while (glyphs.size() > 0 && glyphs.getUnchecked (glyphs.size() - 1)->getRight() >= x + width) | |||||
glyphs.removeLast(); | |||||
appendEllipsis (f, x + width); | |||||
justifyGlyphs (startIndex, glyphs.size() - startIndex, | |||||
x, y, width, height, layout); | |||||
fitLineIntoSpace (startIndex, glyphs.size() - startIndex, | |||||
x, y, width, height, f, layout, minimumHorizontalScale); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
Font font (f); | Font font (f); | ||||
String txt (text.trim()); | String txt (text.trim()); | ||||
const int length = txt.length(); | const int length = txt.length(); | ||||
int numLines = 1; | |||||
const int originalStartIndex = startIndex; | const int originalStartIndex = startIndex; | ||||
int numLines = 1; | |||||
if (length <= 12 && ! txt.containsAnyOf (T(" -\t\r\n"))) | if (length <= 12 && ! txt.containsAnyOf (T(" -\t\r\n"))) | ||||
maximumLines = 1; | maximumLines = 1; | ||||
@@ -86912,23 +86909,18 @@ void GlyphArrangement::addFittedText (const Font& f, | |||||
const float newFontHeight = height / (float) numLines; | const float newFontHeight = height / (float) numLines; | ||||
if (newFontHeight < 8.0f) | |||||
break; | |||||
if (newFontHeight < font.getHeight()) | if (newFontHeight < font.getHeight()) | ||||
{ | { | ||||
font.setHeight (newFontHeight); | |||||
while (glyphs.size() > startIndex) | |||||
glyphs.removeLast(); | |||||
font.setHeight (jmax (8.0f, newFontHeight)); | |||||
removeRangeOfGlyphs (startIndex, -1); | |||||
addLineOfText (font, txt, x, y); | addLineOfText (font, txt, x, y); | ||||
lineWidth = glyphs.getUnchecked (glyphs.size() - 1)->getRight() | lineWidth = glyphs.getUnchecked (glyphs.size() - 1)->getRight() | ||||
- glyphs.getUnchecked (startIndex)->getLeft(); | - glyphs.getUnchecked (startIndex)->getLeft(); | ||||
} | } | ||||
if (numLines > lineWidth / width) | |||||
if (numLines > lineWidth / width || newFontHeight < 8.0f) | |||||
break; | break; | ||||
} | } | ||||
@@ -86945,77 +86937,78 @@ void GlyphArrangement::addFittedText (const Font& f, | |||||
lastLineStartIndex = i; | lastLineStartIndex = i; | ||||
float lineStartX = glyphs.getUnchecked (startIndex)->getLeft(); | float lineStartX = glyphs.getUnchecked (startIndex)->getLeft(); | ||||
while (i < glyphs.size()) | |||||
if (line == numLines - 1) | |||||
{ | { | ||||
lineWidth = (glyphs.getUnchecked (i)->getRight() - lineStartX); | |||||
if (lineWidth > widthPerLine) | |||||
widthPerLine = width; | |||||
i = glyphs.size(); | |||||
} | |||||
else | |||||
{ | |||||
while (i < glyphs.size()) | |||||
{ | { | ||||
// got to a point where the line's too long, so skip forward to find a | |||||
// good place to break it.. | |||||
const int searchStartIndex = i; | |||||
lineWidth = (glyphs.getUnchecked (i)->getRight() - lineStartX); | |||||
while (i < glyphs.size()) | |||||
if (lineWidth > widthPerLine) | |||||
{ | { | ||||
if ((glyphs.getUnchecked (i)->getRight() - lineStartX) * minimumHorizontalScale < width) | |||||
// got to a point where the line's too long, so skip forward to find a | |||||
// good place to break it.. | |||||
const int searchStartIndex = i; | |||||
while (i < glyphs.size()) | |||||
{ | { | ||||
if (glyphs.getUnchecked (i)->isWhitespace() | |||||
|| glyphs.getUnchecked (i)->getCharacter() == T('-')) | |||||
if ((glyphs.getUnchecked (i)->getRight() - lineStartX) * minimumHorizontalScale < width) | |||||
{ | { | ||||
++i; | |||||
break; | |||||
if (glyphs.getUnchecked (i)->isWhitespace() | |||||
|| glyphs.getUnchecked (i)->getCharacter() == T('-')) | |||||
{ | |||||
++i; | |||||
break; | |||||
} | |||||
} | } | ||||
} | |||||
else | |||||
{ | |||||
// can't find a suitable break, so try looking backwards.. | |||||
i = searchStartIndex; | |||||
for (int back = 1; back < jmin (5, i - startIndex - 1); ++back) | |||||
else | |||||
{ | { | ||||
if (glyphs.getUnchecked (i - back)->isWhitespace() | |||||
|| glyphs.getUnchecked (i - back)->getCharacter() == T('-')) | |||||
// can't find a suitable break, so try looking backwards.. | |||||
i = searchStartIndex; | |||||
for (int back = 1; back < jmin (5, i - startIndex - 1); ++back) | |||||
{ | { | ||||
i -= back - 1; | |||||
break; | |||||
if (glyphs.getUnchecked (i - back)->isWhitespace() | |||||
|| glyphs.getUnchecked (i - back)->getCharacter() == T('-')) | |||||
{ | |||||
i -= back - 1; | |||||
break; | |||||
} | |||||
} | } | ||||
break; | |||||
} | } | ||||
break; | |||||
++i; | |||||
} | } | ||||
++i; | |||||
break; | |||||
} | } | ||||
break; | |||||
++i; | |||||
} | } | ||||
++i; | |||||
} | |||||
int wsStart = i; | |||||
while (wsStart > 0 && glyphs.getUnchecked (wsStart - 1)->isWhitespace()) | |||||
--wsStart; | |||||
int wsEnd = i; | |||||
while (wsEnd < glyphs.size() && glyphs.getUnchecked (wsEnd)->isWhitespace()) | |||||
++wsEnd; | |||||
int wsStart = i; | |||||
while (wsStart > 0 && glyphs.getUnchecked (wsStart - 1)->isWhitespace()) | |||||
--wsStart; | |||||
removeRangeOfGlyphs (wsStart, wsEnd - wsStart); | |||||
i = jmax (wsStart, startIndex + 1); | |||||
int wsEnd = i; | |||||
lineWidth = glyphs.getUnchecked (i - 1)->getRight() - lineStartX; | |||||
while (wsEnd < glyphs.size() && glyphs.getUnchecked (wsEnd)->isWhitespace()) | |||||
++wsEnd; | |||||
if (lineWidth > width) | |||||
{ | |||||
stretchRangeOfGlyphs (startIndex, i - startIndex, | |||||
width / lineWidth); | |||||
removeRangeOfGlyphs (wsStart, wsEnd - wsStart); | |||||
i = jmax (wsStart, startIndex + 1); | |||||
} | } | ||||
justifyGlyphs (startIndex, i - startIndex, | |||||
x, lineY, width, font.getHeight(), | |||||
layout.getOnlyHorizontalFlags() | Justification::verticallyCentred); | |||||
i -= fitLineIntoSpace (startIndex, i - startIndex, | |||||
x, lineY, width, font.getHeight(), font, | |||||
layout.getOnlyHorizontalFlags() | Justification::verticallyCentred, | |||||
minimumHorizontalScale); | |||||
startIndex = i; | startIndex = i; | ||||
lineY += font.getHeight(); | lineY += font.getHeight(); | ||||
@@ -87024,32 +87017,7 @@ void GlyphArrangement::addFittedText (const Font& f, | |||||
break; | break; | ||||
} | } | ||||
if (startIndex < glyphs.size()) | |||||
{ | |||||
removeRangeOfGlyphs (startIndex, -1); | |||||
if (startIndex - originalStartIndex > 4) | |||||
{ | |||||
const float lineStartX = glyphs.getUnchecked (lastLineStartIndex)->getLeft(); | |||||
appendEllipsis (font, lineStartX + width); | |||||
lineWidth = glyphs.getUnchecked (startIndex - 1)->getRight() - lineStartX; | |||||
if (lineWidth > width) | |||||
{ | |||||
stretchRangeOfGlyphs (lastLineStartIndex, startIndex - lastLineStartIndex, | |||||
width / lineWidth); | |||||
} | |||||
justifyGlyphs (lastLineStartIndex, startIndex - lastLineStartIndex, | |||||
x, lineY - font.getHeight(), width, font.getHeight(), | |||||
layout.getOnlyHorizontalFlags() | Justification::verticallyCentred); | |||||
} | |||||
startIndex = glyphs.size(); | |||||
} | |||||
justifyGlyphs (originalStartIndex, startIndex - originalStartIndex, | |||||
justifyGlyphs (originalStartIndex, glyphs.size() - originalStartIndex, | |||||
x, y, width, height, layout.getFlags() & ~Justification::horizontallyJustified); | x, y, width, height, layout.getFlags() & ~Justification::horizontallyJustified); | ||||
} | } | ||||
} | } | ||||
@@ -87070,6 +87038,32 @@ void GlyphArrangement::moveRangeOfGlyphs (int startIndex, int num, | |||||
} | } | ||||
} | } | ||||
int GlyphArrangement::fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font& font, | |||||
const Justification& justification, float minimumHorizontalScale) throw() | |||||
{ | |||||
int numDeleted = 0; | |||||
const float lineStartX = glyphs.getUnchecked (start)->getLeft(); | |||||
float lineWidth = glyphs.getUnchecked (start + numGlyphs - 1)->getRight() - lineStartX; | |||||
if (lineWidth > w) | |||||
{ | |||||
if (minimumHorizontalScale < 1.0f) | |||||
{ | |||||
stretchRangeOfGlyphs (start, numGlyphs, jmax (minimumHorizontalScale, w / lineWidth)); | |||||
lineWidth = glyphs.getUnchecked (start + numGlyphs - 1)->getRight() - lineStartX - 0.5f; | |||||
} | |||||
if (lineWidth > w) | |||||
{ | |||||
numDeleted = insertEllipsis (font, lineStartX + w, start, start + numGlyphs); | |||||
numGlyphs -= numDeleted; | |||||
} | |||||
} | |||||
justifyGlyphs (start, numGlyphs, x, y, w, h, justification); | |||||
return numDeleted; | |||||
} | |||||
void GlyphArrangement::stretchRangeOfGlyphs (int startIndex, int num, | void GlyphArrangement::stretchRangeOfGlyphs (int startIndex, int num, | ||||
const float horizontalScaleFactor) throw() | const float horizontalScaleFactor) throw() | ||||
{ | { | ||||
@@ -262822,6 +262816,7 @@ public: | |||||
{ | { | ||||
CGContextRetain (context); | CGContextRetain (context); | ||||
CGContextSetShouldSmoothFonts (context, true); | CGContextSetShouldSmoothFonts (context, true); | ||||
CGContextSetShouldAntialias (context, true); | |||||
CGContextSetBlendMode (context, kCGBlendModeNormal); | CGContextSetBlendMode (context, kCGBlendModeNormal); | ||||
rgbColourSpace = CGColorSpaceCreateDeviceRGB(); | rgbColourSpace = CGColorSpaceCreateDeviceRGB(); | ||||
greyColourSpace = CGColorSpaceCreateDeviceGray(); | greyColourSpace = CGColorSpaceCreateDeviceGray(); | ||||
@@ -267250,6 +267245,7 @@ public: | |||||
{ | { | ||||
CGContextRetain (context); | CGContextRetain (context); | ||||
CGContextSetShouldSmoothFonts (context, true); | CGContextSetShouldSmoothFonts (context, true); | ||||
CGContextSetShouldAntialias (context, true); | |||||
CGContextSetBlendMode (context, kCGBlendModeNormal); | CGContextSetBlendMode (context, kCGBlendModeNormal); | ||||
rgbColourSpace = CGColorSpaceCreateDeviceRGB(); | rgbColourSpace = CGColorSpaceCreateDeviceRGB(); | ||||
greyColourSpace = CGColorSpaceCreateDeviceGray(); | greyColourSpace = CGColorSpaceCreateDeviceGray(); | ||||
@@ -271718,7 +271714,13 @@ public: | |||||
{ | { | ||||
StringArray files; | StringArray files; | ||||
for (unsigned int i = 0; i < [filenames count]; ++i) | for (unsigned int i = 0; i < [filenames count]; ++i) | ||||
files.add (nsStringToJuce ((NSString*) [filenames objectAtIndex: i])); | |||||
{ | |||||
String filename (nsStringToJuce ((NSString*) [filenames objectAtIndex: i])); | |||||
if (filename.containsChar (T(' '))) | |||||
filename = filename.quoted('"'); | |||||
files.add (filename); | |||||
} | |||||
if (files.size() > 0 && JUCEApplication::getInstance() != 0) | if (files.size() > 0 && JUCEApplication::getInstance() != 0) | ||||
{ | { | ||||
@@ -39734,8 +39734,8 @@ public: | |||||
*/ | */ | ||||
void addFittedText (const Font& font, | void addFittedText (const Font& font, | ||||
const String& text, | const String& text, | ||||
float x, float y, | |||||
float width, float height, | |||||
const float x, const float y, | |||||
const float width, const float height, | |||||
const Justification& layout, | const Justification& layout, | ||||
int maximumLinesToUse, | int maximumLinesToUse, | ||||
const float minimumHorizontalScale = 0.7f) throw(); | const float minimumHorizontalScale = 0.7f) throw(); | ||||
@@ -39839,7 +39839,9 @@ public: | |||||
private: | private: | ||||
OwnedArray <PositionedGlyph> glyphs; | OwnedArray <PositionedGlyph> glyphs; | ||||
void appendEllipsis (const Font& font, const float maxXPixels) throw(); | |||||
int insertEllipsis (const Font& font, const float maxXPos, const int startIndex, int endIndex) throw(); | |||||
int fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font& font, | |||||
const Justification& justification, float minimumHorizontalScale) throw(); | |||||
void spreadOutLine (const int start, const int numGlyphs, const float targetWidth) throw(); | void spreadOutLine (const int start, const int numGlyphs, const float targetWidth) throw(); | ||||
}; | }; | ||||
@@ -200,7 +200,7 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, | |||||
{ | { | ||||
// curtail the string if it's too wide.. | // curtail the string if it's too wide.. | ||||
if (useEllipsis && textLen > 3 && glyphs.size() >= 3) | if (useEllipsis && textLen > 3 && glyphs.size() >= 3) | ||||
appendEllipsis (font, xOffset + maxWidthPixels); | |||||
insertEllipsis (font, xOffset + maxWidthPixels, 0, glyphs.size()); | |||||
break; | break; | ||||
} | } | ||||
@@ -220,8 +220,11 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, | |||||
} | } | ||||
} | } | ||||
void GlyphArrangement::appendEllipsis (const Font& font, const float maxXPixels) throw() | |||||
int GlyphArrangement::insertEllipsis (const Font& font, const float maxXPos, | |||||
const int startIndex, int endIndex) throw() | |||||
{ | { | ||||
int numDeleted = 0; | |||||
if (glyphs.size() > 0) | if (glyphs.size() > 0) | ||||
{ | { | ||||
Array<int> dotGlyphs; | Array<int> dotGlyphs; | ||||
@@ -231,15 +234,16 @@ void GlyphArrangement::appendEllipsis (const Font& font, const float maxXPixels) | |||||
const float dx = dotXs[1]; | const float dx = dotXs[1]; | ||||
float xOffset = 0.0f, yOffset = 0.0f; | float xOffset = 0.0f, yOffset = 0.0f; | ||||
for (int dotPos = 3; --dotPos >= 0 && glyphs.size() > 0;) | |||||
while (endIndex > startIndex) | |||||
{ | { | ||||
const PositionedGlyph* pg = glyphs.getUnchecked (glyphs.size() - 1); | |||||
const PositionedGlyph* pg = glyphs.getUnchecked (--endIndex); | |||||
xOffset = pg->x; | xOffset = pg->x; | ||||
yOffset = pg->y; | yOffset = pg->y; | ||||
glyphs.removeLast(); | |||||
glyphs.remove (endIndex); | |||||
++numDeleted; | |||||
if (xOffset + dx * 3 <= maxXPixels) | |||||
if (xOffset + dx * 3 <= maxXPos) | |||||
break; | break; | ||||
} | } | ||||
@@ -252,11 +256,17 @@ void GlyphArrangement::appendEllipsis (const Font& font, const float maxXPixels) | |||||
pg->font = font; | pg->font = font; | ||||
pg->character = '.'; | pg->character = '.'; | ||||
pg->glyph = dotGlyphs.getFirst(); | pg->glyph = dotGlyphs.getFirst(); | ||||
glyphs.add (pg); | |||||
glyphs.insert (endIndex++, pg); | |||||
--numDeleted; | |||||
xOffset += dx; | xOffset += dx; | ||||
if (xOffset > maxXPos) | |||||
break; | |||||
} | } | ||||
} | } | ||||
return numDeleted; | |||||
} | } | ||||
void GlyphArrangement::addJustifiedText (const Font& font, | void GlyphArrangement::addJustifiedText (const Font& font, | ||||
@@ -343,8 +353,8 @@ void GlyphArrangement::addJustifiedText (const Font& font, | |||||
void GlyphArrangement::addFittedText (const Font& f, | void GlyphArrangement::addFittedText (const Font& f, | ||||
const String& text, | const String& text, | ||||
float x, float y, | |||||
float width, float height, | |||||
const float x, const float y, | |||||
const float width, const float height, | |||||
const Justification& layout, | const Justification& layout, | ||||
int maximumLines, | int maximumLines, | ||||
const float minimumHorizontalScale) throw() | const float minimumHorizontalScale) throw() | ||||
@@ -392,37 +402,24 @@ void GlyphArrangement::addFittedText (const Font& f, | |||||
if (lineWidth * minimumHorizontalScale < width) | if (lineWidth * minimumHorizontalScale < width) | ||||
{ | { | ||||
if (lineWidth > width) | if (lineWidth > width) | ||||
{ | |||||
stretchRangeOfGlyphs (startIndex, glyphs.size() - startIndex, | stretchRangeOfGlyphs (startIndex, glyphs.size() - startIndex, | ||||
width / lineWidth); | width / lineWidth); | ||||
} | |||||
justifyGlyphs (startIndex, glyphs.size() - startIndex, | justifyGlyphs (startIndex, glyphs.size() - startIndex, | ||||
x, y, width, height, layout); | x, y, width, height, layout); | ||||
} | } | ||||
else if (maximumLines <= 1) | else if (maximumLines <= 1) | ||||
{ | { | ||||
const float ratio = jmax (minimumHorizontalScale, width / lineWidth); | |||||
stretchRangeOfGlyphs (startIndex, glyphs.size() - startIndex, ratio); | |||||
while (glyphs.size() > 0 && glyphs.getUnchecked (glyphs.size() - 1)->getRight() >= x + width) | |||||
glyphs.removeLast(); | |||||
appendEllipsis (f, x + width); | |||||
justifyGlyphs (startIndex, glyphs.size() - startIndex, | |||||
x, y, width, height, layout); | |||||
fitLineIntoSpace (startIndex, glyphs.size() - startIndex, | |||||
x, y, width, height, f, layout, minimumHorizontalScale); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
Font font (f); | Font font (f); | ||||
String txt (text.trim()); | String txt (text.trim()); | ||||
const int length = txt.length(); | const int length = txt.length(); | ||||
int numLines = 1; | |||||
const int originalStartIndex = startIndex; | const int originalStartIndex = startIndex; | ||||
int numLines = 1; | |||||
if (length <= 12 && ! txt.containsAnyOf (T(" -\t\r\n"))) | if (length <= 12 && ! txt.containsAnyOf (T(" -\t\r\n"))) | ||||
maximumLines = 1; | maximumLines = 1; | ||||
@@ -435,23 +432,18 @@ void GlyphArrangement::addFittedText (const Font& f, | |||||
const float newFontHeight = height / (float) numLines; | const float newFontHeight = height / (float) numLines; | ||||
if (newFontHeight < 8.0f) | |||||
break; | |||||
if (newFontHeight < font.getHeight()) | if (newFontHeight < font.getHeight()) | ||||
{ | { | ||||
font.setHeight (newFontHeight); | |||||
while (glyphs.size() > startIndex) | |||||
glyphs.removeLast(); | |||||
font.setHeight (jmax (8.0f, newFontHeight)); | |||||
removeRangeOfGlyphs (startIndex, -1); | |||||
addLineOfText (font, txt, x, y); | addLineOfText (font, txt, x, y); | ||||
lineWidth = glyphs.getUnchecked (glyphs.size() - 1)->getRight() | lineWidth = glyphs.getUnchecked (glyphs.size() - 1)->getRight() | ||||
- glyphs.getUnchecked (startIndex)->getLeft(); | - glyphs.getUnchecked (startIndex)->getLeft(); | ||||
} | } | ||||
if (numLines > lineWidth / width) | |||||
if (numLines > lineWidth / width || newFontHeight < 8.0f) | |||||
break; | break; | ||||
} | } | ||||
@@ -468,77 +460,78 @@ void GlyphArrangement::addFittedText (const Font& f, | |||||
lastLineStartIndex = i; | lastLineStartIndex = i; | ||||
float lineStartX = glyphs.getUnchecked (startIndex)->getLeft(); | float lineStartX = glyphs.getUnchecked (startIndex)->getLeft(); | ||||
while (i < glyphs.size()) | |||||
if (line == numLines - 1) | |||||
{ | { | ||||
lineWidth = (glyphs.getUnchecked (i)->getRight() - lineStartX); | |||||
if (lineWidth > widthPerLine) | |||||
widthPerLine = width; | |||||
i = glyphs.size(); | |||||
} | |||||
else | |||||
{ | |||||
while (i < glyphs.size()) | |||||
{ | { | ||||
// got to a point where the line's too long, so skip forward to find a | |||||
// good place to break it.. | |||||
const int searchStartIndex = i; | |||||
lineWidth = (glyphs.getUnchecked (i)->getRight() - lineStartX); | |||||
while (i < glyphs.size()) | |||||
if (lineWidth > widthPerLine) | |||||
{ | { | ||||
if ((glyphs.getUnchecked (i)->getRight() - lineStartX) * minimumHorizontalScale < width) | |||||
// got to a point where the line's too long, so skip forward to find a | |||||
// good place to break it.. | |||||
const int searchStartIndex = i; | |||||
while (i < glyphs.size()) | |||||
{ | { | ||||
if (glyphs.getUnchecked (i)->isWhitespace() | |||||
|| glyphs.getUnchecked (i)->getCharacter() == T('-')) | |||||
if ((glyphs.getUnchecked (i)->getRight() - lineStartX) * minimumHorizontalScale < width) | |||||
{ | { | ||||
++i; | |||||
break; | |||||
if (glyphs.getUnchecked (i)->isWhitespace() | |||||
|| glyphs.getUnchecked (i)->getCharacter() == T('-')) | |||||
{ | |||||
++i; | |||||
break; | |||||
} | |||||
} | } | ||||
} | |||||
else | |||||
{ | |||||
// can't find a suitable break, so try looking backwards.. | |||||
i = searchStartIndex; | |||||
for (int back = 1; back < jmin (5, i - startIndex - 1); ++back) | |||||
else | |||||
{ | { | ||||
if (glyphs.getUnchecked (i - back)->isWhitespace() | |||||
|| glyphs.getUnchecked (i - back)->getCharacter() == T('-')) | |||||
// can't find a suitable break, so try looking backwards.. | |||||
i = searchStartIndex; | |||||
for (int back = 1; back < jmin (5, i - startIndex - 1); ++back) | |||||
{ | { | ||||
i -= back - 1; | |||||
break; | |||||
if (glyphs.getUnchecked (i - back)->isWhitespace() | |||||
|| glyphs.getUnchecked (i - back)->getCharacter() == T('-')) | |||||
{ | |||||
i -= back - 1; | |||||
break; | |||||
} | |||||
} | } | ||||
break; | |||||
} | } | ||||
break; | |||||
++i; | |||||
} | } | ||||
++i; | |||||
break; | |||||
} | } | ||||
break; | |||||
++i; | |||||
} | } | ||||
++i; | |||||
} | |||||
int wsStart = i; | |||||
while (wsStart > 0 && glyphs.getUnchecked (wsStart - 1)->isWhitespace()) | |||||
--wsStart; | |||||
int wsStart = i; | |||||
while (wsStart > 0 && glyphs.getUnchecked (wsStart - 1)->isWhitespace()) | |||||
--wsStart; | |||||
int wsEnd = i; | |||||
int wsEnd = i; | |||||
while (wsEnd < glyphs.size() && glyphs.getUnchecked (wsEnd)->isWhitespace()) | |||||
++wsEnd; | |||||
while (wsEnd < glyphs.size() && glyphs.getUnchecked (wsEnd)->isWhitespace()) | |||||
++wsEnd; | |||||
removeRangeOfGlyphs (wsStart, wsEnd - wsStart); | |||||
i = jmax (wsStart, startIndex + 1); | |||||
lineWidth = glyphs.getUnchecked (i - 1)->getRight() - lineStartX; | |||||
if (lineWidth > width) | |||||
{ | |||||
stretchRangeOfGlyphs (startIndex, i - startIndex, | |||||
width / lineWidth); | |||||
removeRangeOfGlyphs (wsStart, wsEnd - wsStart); | |||||
i = jmax (wsStart, startIndex + 1); | |||||
} | } | ||||
justifyGlyphs (startIndex, i - startIndex, | |||||
x, lineY, width, font.getHeight(), | |||||
layout.getOnlyHorizontalFlags() | Justification::verticallyCentred); | |||||
i -= fitLineIntoSpace (startIndex, i - startIndex, | |||||
x, lineY, width, font.getHeight(), font, | |||||
layout.getOnlyHorizontalFlags() | Justification::verticallyCentred, | |||||
minimumHorizontalScale); | |||||
startIndex = i; | startIndex = i; | ||||
lineY += font.getHeight(); | lineY += font.getHeight(); | ||||
@@ -547,32 +540,7 @@ void GlyphArrangement::addFittedText (const Font& f, | |||||
break; | break; | ||||
} | } | ||||
if (startIndex < glyphs.size()) | |||||
{ | |||||
removeRangeOfGlyphs (startIndex, -1); | |||||
if (startIndex - originalStartIndex > 4) | |||||
{ | |||||
const float lineStartX = glyphs.getUnchecked (lastLineStartIndex)->getLeft(); | |||||
appendEllipsis (font, lineStartX + width); | |||||
lineWidth = glyphs.getUnchecked (startIndex - 1)->getRight() - lineStartX; | |||||
if (lineWidth > width) | |||||
{ | |||||
stretchRangeOfGlyphs (lastLineStartIndex, startIndex - lastLineStartIndex, | |||||
width / lineWidth); | |||||
} | |||||
justifyGlyphs (lastLineStartIndex, startIndex - lastLineStartIndex, | |||||
x, lineY - font.getHeight(), width, font.getHeight(), | |||||
layout.getOnlyHorizontalFlags() | Justification::verticallyCentred); | |||||
} | |||||
startIndex = glyphs.size(); | |||||
} | |||||
justifyGlyphs (originalStartIndex, startIndex - originalStartIndex, | |||||
justifyGlyphs (originalStartIndex, glyphs.size() - originalStartIndex, | |||||
x, y, width, height, layout.getFlags() & ~Justification::horizontallyJustified); | x, y, width, height, layout.getFlags() & ~Justification::horizontallyJustified); | ||||
} | } | ||||
} | } | ||||
@@ -594,6 +562,32 @@ void GlyphArrangement::moveRangeOfGlyphs (int startIndex, int num, | |||||
} | } | ||||
} | } | ||||
int GlyphArrangement::fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font& font, | |||||
const Justification& justification, float minimumHorizontalScale) throw() | |||||
{ | |||||
int numDeleted = 0; | |||||
const float lineStartX = glyphs.getUnchecked (start)->getLeft(); | |||||
float lineWidth = glyphs.getUnchecked (start + numGlyphs - 1)->getRight() - lineStartX; | |||||
if (lineWidth > w) | |||||
{ | |||||
if (minimumHorizontalScale < 1.0f) | |||||
{ | |||||
stretchRangeOfGlyphs (start, numGlyphs, jmax (minimumHorizontalScale, w / lineWidth)); | |||||
lineWidth = glyphs.getUnchecked (start + numGlyphs - 1)->getRight() - lineStartX - 0.5f; | |||||
} | |||||
if (lineWidth > w) | |||||
{ | |||||
numDeleted = insertEllipsis (font, lineStartX + w, start, start + numGlyphs); | |||||
numGlyphs -= numDeleted; | |||||
} | |||||
} | |||||
justifyGlyphs (start, numGlyphs, x, y, w, h, justification); | |||||
return numDeleted; | |||||
} | |||||
void GlyphArrangement::stretchRangeOfGlyphs (int startIndex, int num, | void GlyphArrangement::stretchRangeOfGlyphs (int startIndex, int num, | ||||
const float horizontalScaleFactor) throw() | const float horizontalScaleFactor) throw() | ||||
{ | { | ||||
@@ -201,8 +201,8 @@ public: | |||||
*/ | */ | ||||
void addFittedText (const Font& font, | void addFittedText (const Font& font, | ||||
const String& text, | const String& text, | ||||
float x, float y, | |||||
float width, float height, | |||||
const float x, const float y, | |||||
const float width, const float height, | |||||
const Justification& layout, | const Justification& layout, | ||||
int maximumLinesToUse, | int maximumLinesToUse, | ||||
const float minimumHorizontalScale = 0.7f) throw(); | const float minimumHorizontalScale = 0.7f) throw(); | ||||
@@ -312,7 +312,9 @@ public: | |||||
private: | private: | ||||
OwnedArray <PositionedGlyph> glyphs; | OwnedArray <PositionedGlyph> glyphs; | ||||
void appendEllipsis (const Font& font, const float maxXPixels) throw(); | |||||
int insertEllipsis (const Font& font, const float maxXPos, const int startIndex, int endIndex) throw(); | |||||
int fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font& font, | |||||
const Justification& justification, float minimumHorizontalScale) throw(); | |||||
void spreadOutLine (const int start, const int numGlyphs, const float targetWidth) throw(); | void spreadOutLine (const int start, const int numGlyphs, const float targetWidth) throw(); | ||||
}; | }; | ||||
@@ -73,6 +73,7 @@ public: | |||||
{ | { | ||||
CGContextRetain (context); | CGContextRetain (context); | ||||
CGContextSetShouldSmoothFonts (context, true); | CGContextSetShouldSmoothFonts (context, true); | ||||
CGContextSetShouldAntialias (context, true); | |||||
CGContextSetBlendMode (context, kCGBlendModeNormal); | CGContextSetBlendMode (context, kCGBlendModeNormal); | ||||
rgbColourSpace = CGColorSpaceCreateDeviceRGB(); | rgbColourSpace = CGColorSpaceCreateDeviceRGB(); | ||||
greyColourSpace = CGColorSpaceCreateDeviceGray(); | greyColourSpace = CGColorSpaceCreateDeviceGray(); | ||||
@@ -105,7 +105,13 @@ public: | |||||
{ | { | ||||
StringArray files; | StringArray files; | ||||
for (unsigned int i = 0; i < [filenames count]; ++i) | for (unsigned int i = 0; i < [filenames count]; ++i) | ||||
files.add (nsStringToJuce ((NSString*) [filenames objectAtIndex: i])); | |||||
{ | |||||
String filename (nsStringToJuce ((NSString*) [filenames objectAtIndex: i])); | |||||
if (filename.containsChar (T(' '))) | |||||
filename = filename.quoted('"'); | |||||
files.add (filename); | |||||
} | |||||
if (files.size() > 0 && JUCEApplication::getInstance() != 0) | if (files.size() > 0 && JUCEApplication::getInstance() != 0) | ||||
{ | { | ||||