31 int getLength (
const Array<AttributedString::Attribute>& atts)
noexcept
33 return atts.size() != 0 ? atts.getReference (atts.size() - 1).range.getEnd() : 0;
36 void splitAttributeRanges (Array<AttributedString::Attribute>& atts,
int position)
38 for (
int i = atts.size(); --i >= 0;)
40 const auto& att = atts.getUnchecked (i);
41 auto offset = position - att.range.getStart();
45 if (offset > 0 && position < att.range.getEnd())
47 atts.insert (i + 1, AttributedString::Attribute (att));
48 atts.getReference (i).range.setEnd (position);
49 atts.getReference (i + 1).range.setStart (position);
57 inline bool areInvariantsMaintained (
const String& text,
const Array<AttributedString::Attribute>& atts)
62 if (atts.getFirst().range.getStart() != 0)
65 if (atts.getLast().range.getEnd() != text.length())
68 for (
auto it =
std::next (atts.begin()); it != atts.end(); ++it)
69 if (it->range.getStart() !=
std::prev (it)->range.getEnd())
75 Range<int> splitAttributeRanges (Array<AttributedString::Attribute>& atts, Range<int> newRange)
77 newRange = newRange.getIntersectionWith ({ 0, getLength (atts) });
79 if (! newRange.isEmpty())
81 splitAttributeRanges (atts, newRange.getStart());
82 splitAttributeRanges (atts, newRange.getEnd());
88 void mergeAdjacentRanges (Array<AttributedString::Attribute>& atts)
90 for (
int i = atts.size() - 1; --i >= 0;)
92 auto& a1 = atts.getReference (i);
93 auto& a2 = atts.getReference (i + 1);
95 if (a1.colour == a2.colour && a1.font == a2.font)
97 a1.range.setEnd (a2.range.getEnd());
100 if (i < atts.size() - 1)
106 void appendRange (Array<AttributedString::Attribute>& atts,
107 int length,
const Font* f,
const Colour* c)
109 if (atts.size() == 0)
111 atts.add ({ Range<int> (0, length), f !=
nullptr ? *f : Font(), c !=
nullptr ? *c : Colour (0xff000000) });
115 auto start = getLength (atts);
116 atts.add ({ Range<int> (start, start + length),
117 f !=
nullptr ? *f : atts.getReference (atts.size() - 1).font,
118 c !=
nullptr ? *c : atts.getReference (atts.size() - 1).colour });
120 mergeAdjacentRanges (atts);
124 void applyFontAndColour (Array<AttributedString::Attribute>& atts,
125 Range<int> range,
const Font* f,
const Colour* c)
127 range = splitAttributeRanges (atts, range);
129 for (
auto& att : atts)
131 if (range.getStart() < att.range.getEnd())
133 if (range.getEnd() <= att.range.getStart())
136 if (c !=
nullptr) att.colour = *c;
137 if (f !=
nullptr) att.font = *f;
141 mergeAdjacentRanges (atts);
144 void truncate (Array<AttributedString::Attribute>& atts,
int newLength)
146 splitAttributeRanges (atts, newLength);
148 for (
int i = atts.size(); --i >= 0;)
149 if (atts.getReference (i).range.getStart() >= newLength)
156 : range (r), font (f), colour (c)
163 auto newLength = newText.
length();
164 auto oldLength = getLength (attributes);
166 if (newLength > oldLength)
167 appendRange (attributes, newLength - oldLength,
nullptr,
nullptr);
168 else if (newLength < oldLength)
172 jassert (areInvariantsMaintained (text, attributes));
177 text += textToAppend;
178 appendRange (attributes, textToAppend.
length(),
nullptr,
nullptr);
179 jassert (areInvariantsMaintained (text, attributes));
184 text += textToAppend;
185 appendRange (attributes, textToAppend.
length(), &font,
nullptr);
186 jassert (areInvariantsMaintained (text, attributes));
191 text += textToAppend;
192 appendRange (attributes, textToAppend.
length(),
nullptr, &colour);
193 jassert (areInvariantsMaintained (text, attributes));
198 text += textToAppend;
199 appendRange (attributes, textToAppend.
length(), &font, &colour);
200 jassert (areInvariantsMaintained (text, attributes));
205 auto originalLength = getLength (attributes);
206 auto originalNumAtts = attributes.size();
208 attributes.addArray (other.attributes);
210 for (
auto i = originalNumAtts; i < attributes.size(); ++i)
211 attributes.getReference (i).range += originalLength;
213 mergeAdjacentRanges (attributes);
214 jassert (areInvariantsMaintained (text, attributes));
225 justification = newJustification;
230 wordWrap = newWordWrap;
235 readingDirection = newReadingDirection;
240 lineSpacing = newLineSpacing;
245 applyFontAndColour (attributes, range,
nullptr, &colour);
246 jassert (areInvariantsMaintained (text, attributes));
251 applyFontAndColour (attributes, range, &font,
nullptr);
252 jassert (areInvariantsMaintained (text, attributes));
257 setColour ({ 0, getLength (attributes) }, colour);
258 jassert (areInvariantsMaintained (text, attributes));
263 setFont ({ 0, getLength (attributes) }, font);
264 jassert (areInvariantsMaintained (text, attributes));
271 jassert (text.length() == getLength (attributes));
273 if (! g.getInternalContext().drawTextLayout (*
this, area))
277 layout.
draw (g, area);
A text string with a set of colour/font settings that are associated with sub-ranges of the text.
void setColour(Range< int > range, Colour colour)
Adds a colour attribute for the specified range.
void setLineSpacing(float newLineSpacing) noexcept
Sets an extra line-spacing distance.
void clear()
Resets the string, clearing all text and attributes.
void draw(Graphics &g, const Rectangle< float > &area) const
Draws this string within the given area.
void setReadingDirection(ReadingDirection newReadingDirection) noexcept
Sets the reading direction that should be used for the text.
void append(const String &textToAppend)
Appends some text (with a default font and colour).
ReadingDirection
Types of reading direction that can be used.
WordWrap
Types of word-wrap behaviour.
void setText(const String &newText)
Replaces all the text.
void setJustification(Justification newJustification) noexcept
Sets the justification that should be used for laying-out the text.
void setWordWrap(WordWrap newWordWrap) noexcept
Sets the word-wrapping behaviour.
void setFont(Range< int > range, const Font &font)
Adds a font attribute for the specified range.
Represents a colour, also including a transparency value.
Represents a particular font, including its size, style, etc.
A graphics context, used for drawing a component or image.
bool clipRegionIntersects(Rectangle< int > area) const
Checks whether a rectangle overlaps the context's clipping region.
Represents a type of justification to be used when positioning graphical items.
A general-purpose range object, that simply represents any linear range with a start and end point.
Manages a rectangle and allows geometric operations to be performed on it.
Rectangle< int > getSmallestIntegerContainer() const noexcept
Returns the smallest integer-aligned rectangle that completely contains this one.
ValueType getWidth() const noexcept
Returns the width of the rectangle.
int length() const noexcept
Returns the number of characters in the string.
A Pre-formatted piece of text, which may contain multiple fonts and colours.
void draw(Graphics &, Rectangle< float > area) const
Draws the layout within the specified area.
void createLayout(const AttributedString &, float maxWidth)
Creates a layout from the given attributed string.