123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- /*
- ==============================================================================
- This file is part of the JUCE library.
- Copyright (c) 2017 - ROLI Ltd.
- JUCE is an open source library subject to commercial or open-source
- licensing.
- By using JUCE, you agree to the terms of both the JUCE 5 End-User License
- Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
- 27th April 2017).
- End User License Agreement: www.juce.com/juce-5-licence
- Privacy Policy: www.juce.com/juce-5-privacy-policy
- Or: You may also use this code under the terms of the GPL v3 (see
- www.gnu.org/licenses).
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
- ==============================================================================
- */
- namespace juce
- {
- namespace
- {
- int getLength (const Array<AttributedString::Attribute>& atts) noexcept
- {
- return atts.size() != 0 ? atts.getReference (atts.size() - 1).range.getEnd() : 0;
- }
- void splitAttributeRanges (Array<AttributedString::Attribute>& atts, int position)
- {
- for (int i = atts.size(); --i >= 0;)
- {
- const auto& att = atts.getUnchecked (i);
- auto offset = position - att.range.getStart();
- if (offset >= 0)
- {
- if (offset > 0 && position < att.range.getEnd())
- {
- atts.insert (i + 1, AttributedString::Attribute (att));
- atts.getReference (i).range.setEnd (position);
- atts.getReference (i + 1).range.setStart (position);
- }
- break;
- }
- }
- }
- Range<int> splitAttributeRanges (Array<AttributedString::Attribute>& atts, Range<int> newRange)
- {
- newRange = newRange.getIntersectionWith ({ 0, getLength (atts) });
- if (! newRange.isEmpty())
- {
- splitAttributeRanges (atts, newRange.getStart());
- splitAttributeRanges (atts, newRange.getEnd());
- }
- return newRange;
- }
- void mergeAdjacentRanges (Array<AttributedString::Attribute>& atts)
- {
- for (int i = atts.size() - 1; --i >= 0;)
- {
- auto& a1 = atts.getReference (i);
- auto& a2 = atts.getReference (i + 1);
- if (a1.colour == a2.colour && a1.font == a2.font)
- {
- a1.range.setEnd (a2.range.getEnd());
- atts.remove (i + 1);
- if (i < atts.size() - 1)
- ++i;
- }
- }
- }
- void appendRange (Array<AttributedString::Attribute>& atts,
- int length, const Font* f, const Colour* c)
- {
- if (atts.size() == 0)
- {
- atts.add ({ Range<int> (0, length), f != nullptr ? *f : Font(), c != nullptr ? *c : Colour (0xff000000) });
- }
- else
- {
- auto start = getLength (atts);
- atts.add ({ Range<int> (start, start + length),
- f != nullptr ? *f : atts.getReference (atts.size() - 1).font,
- c != nullptr ? *c : atts.getReference (atts.size() - 1).colour });
- mergeAdjacentRanges (atts);
- }
- }
- void applyFontAndColour (Array<AttributedString::Attribute>& atts,
- Range<int> range, const Font* f, const Colour* c)
- {
- range = splitAttributeRanges (atts, range);
- for (auto& att : atts)
- {
- if (range.getStart() < att.range.getEnd())
- {
- if (range.getEnd() <= att.range.getStart())
- break;
- if (c != nullptr) att.colour = *c;
- if (f != nullptr) att.font = *f;
- }
- }
- mergeAdjacentRanges (atts);
- }
- void truncate (Array<AttributedString::Attribute>& atts, int newLength)
- {
- splitAttributeRanges (atts, newLength);
- for (int i = atts.size(); --i >= 0;)
- if (atts.getReference (i).range.getStart() >= newLength)
- atts.remove (i);
- }
- }
- //==============================================================================
- AttributedString::Attribute::Attribute (Range<int> r, const Font& f, Colour c) noexcept
- : range (r), font (f), colour (c)
- {
- }
- //==============================================================================
- void AttributedString::setText (const String& newText)
- {
- auto newLength = newText.length();
- auto oldLength = getLength (attributes);
- if (newLength > oldLength)
- appendRange (attributes, newLength - oldLength, nullptr, nullptr);
- else if (newLength < oldLength)
- truncate (attributes, newLength);
- text = newText;
- }
- void AttributedString::append (const String& textToAppend)
- {
- text += textToAppend;
- appendRange (attributes, textToAppend.length(), nullptr, nullptr);
- }
- void AttributedString::append (const String& textToAppend, const Font& font)
- {
- text += textToAppend;
- appendRange (attributes, textToAppend.length(), &font, nullptr);
- }
- void AttributedString::append (const String& textToAppend, Colour colour)
- {
- text += textToAppend;
- appendRange (attributes, textToAppend.length(), nullptr, &colour);
- }
- void AttributedString::append (const String& textToAppend, const Font& font, Colour colour)
- {
- text += textToAppend;
- appendRange (attributes, textToAppend.length(), &font, &colour);
- }
- void AttributedString::append (const AttributedString& other)
- {
- auto originalLength = getLength (attributes);
- auto originalNumAtts = attributes.size();
- text += other.text;
- attributes.addArray (other.attributes);
- for (auto i = originalNumAtts; i < attributes.size(); ++i)
- attributes.getReference (i).range += originalLength;
- mergeAdjacentRanges (attributes);
- }
- void AttributedString::clear()
- {
- text.clear();
- attributes.clear();
- }
- void AttributedString::setJustification (Justification newJustification) noexcept
- {
- justification = newJustification;
- }
- void AttributedString::setWordWrap (WordWrap newWordWrap) noexcept
- {
- wordWrap = newWordWrap;
- }
- void AttributedString::setReadingDirection (ReadingDirection newReadingDirection) noexcept
- {
- readingDirection = newReadingDirection;
- }
- void AttributedString::setLineSpacing (const float newLineSpacing) noexcept
- {
- lineSpacing = newLineSpacing;
- }
- void AttributedString::setColour (Range<int> range, Colour colour)
- {
- applyFontAndColour (attributes, range, nullptr, &colour);
- }
- void AttributedString::setFont (Range<int> range, const Font& font)
- {
- applyFontAndColour (attributes, range, &font, nullptr);
- }
- void AttributedString::setColour (Colour colour)
- {
- setColour ({ 0, getLength (attributes) }, colour);
- }
- void AttributedString::setFont (const Font& font)
- {
- setFont ({ 0, getLength (attributes) }, font);
- }
- void AttributedString::draw (Graphics& g, const Rectangle<float>& area) const
- {
- if (text.isNotEmpty() && g.clipRegionIntersects (area.getSmallestIntegerContainer()))
- {
- jassert (text.length() == getLength (attributes));
- if (! g.getInternalContext().drawTextLayout (*this, area))
- {
- TextLayout layout;
- layout.createLayout (*this, area.getWidth());
- layout.draw (g, area);
- }
- }
- }
- } // namespace juce
|