Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
7.3KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. namespace juce
  14. {
  15. namespace
  16. {
  17. int getLength (const Array<AttributedString::Attribute>& atts) noexcept
  18. {
  19. return atts.size() != 0 ? atts.getReference (atts.size() - 1).range.getEnd() : 0;
  20. }
  21. void splitAttributeRanges (Array<AttributedString::Attribute>& atts, int position)
  22. {
  23. for (int i = atts.size(); --i >= 0;)
  24. {
  25. const auto& att = atts.getUnchecked (i);
  26. auto offset = position - att.range.getStart();
  27. if (offset >= 0)
  28. {
  29. if (offset > 0 && position < att.range.getEnd())
  30. {
  31. atts.insert (i + 1, AttributedString::Attribute (att));
  32. atts.getReference (i).range.setEnd (position);
  33. atts.getReference (i + 1).range.setStart (position);
  34. }
  35. break;
  36. }
  37. }
  38. }
  39. Range<int> splitAttributeRanges (Array<AttributedString::Attribute>& atts, Range<int> newRange)
  40. {
  41. newRange = newRange.getIntersectionWith ({ 0, getLength (atts) });
  42. if (! newRange.isEmpty())
  43. {
  44. splitAttributeRanges (atts, newRange.getStart());
  45. splitAttributeRanges (atts, newRange.getEnd());
  46. }
  47. return newRange;
  48. }
  49. void mergeAdjacentRanges (Array<AttributedString::Attribute>& atts)
  50. {
  51. for (int i = atts.size() - 1; --i >= 0;)
  52. {
  53. auto& a1 = atts.getReference (i);
  54. auto& a2 = atts.getReference (i + 1);
  55. if (a1.colour == a2.colour && a1.font == a2.font)
  56. {
  57. a1.range.setEnd (a2.range.getEnd());
  58. atts.remove (i + 1);
  59. if (i < atts.size() - 1)
  60. ++i;
  61. }
  62. }
  63. }
  64. void appendRange (Array<AttributedString::Attribute>& atts,
  65. int length, const Font* f, const Colour* c)
  66. {
  67. if (atts.size() == 0)
  68. {
  69. atts.add ({ Range<int> (0, length), f != nullptr ? *f : Font(), c != nullptr ? *c : Colour (0xff000000) });
  70. }
  71. else
  72. {
  73. auto start = getLength (atts);
  74. atts.add ({ Range<int> (start, start + length),
  75. f != nullptr ? *f : atts.getReference (atts.size() - 1).font,
  76. c != nullptr ? *c : atts.getReference (atts.size() - 1).colour });
  77. mergeAdjacentRanges (atts);
  78. }
  79. }
  80. void applyFontAndColour (Array<AttributedString::Attribute>& atts,
  81. Range<int> range, const Font* f, const Colour* c)
  82. {
  83. range = splitAttributeRanges (atts, range);
  84. for (auto& att : atts)
  85. {
  86. if (range.getStart() < att.range.getEnd())
  87. {
  88. if (range.getEnd() <= att.range.getStart())
  89. break;
  90. if (c != nullptr) att.colour = *c;
  91. if (f != nullptr) att.font = *f;
  92. }
  93. }
  94. mergeAdjacentRanges (atts);
  95. }
  96. void truncate (Array<AttributedString::Attribute>& atts, int newLength)
  97. {
  98. splitAttributeRanges (atts, newLength);
  99. for (int i = atts.size(); --i >= 0;)
  100. if (atts.getReference (i).range.getStart() >= newLength)
  101. atts.remove (i);
  102. }
  103. }
  104. //==============================================================================
  105. AttributedString::Attribute::Attribute (Range<int> r, const Font& f, Colour c) noexcept
  106. : range (r), font (f), colour (c)
  107. {
  108. }
  109. //==============================================================================
  110. void AttributedString::setText (const String& newText)
  111. {
  112. auto newLength = newText.length();
  113. auto oldLength = getLength (attributes);
  114. if (newLength > oldLength)
  115. appendRange (attributes, newLength - oldLength, nullptr, nullptr);
  116. else if (newLength < oldLength)
  117. truncate (attributes, newLength);
  118. text = newText;
  119. }
  120. void AttributedString::append (const String& textToAppend)
  121. {
  122. text += textToAppend;
  123. appendRange (attributes, textToAppend.length(), nullptr, nullptr);
  124. }
  125. void AttributedString::append (const String& textToAppend, const Font& font)
  126. {
  127. text += textToAppend;
  128. appendRange (attributes, textToAppend.length(), &font, nullptr);
  129. }
  130. void AttributedString::append (const String& textToAppend, Colour colour)
  131. {
  132. text += textToAppend;
  133. appendRange (attributes, textToAppend.length(), nullptr, &colour);
  134. }
  135. void AttributedString::append (const String& textToAppend, const Font& font, Colour colour)
  136. {
  137. text += textToAppend;
  138. appendRange (attributes, textToAppend.length(), &font, &colour);
  139. }
  140. void AttributedString::append (const AttributedString& other)
  141. {
  142. auto originalLength = getLength (attributes);
  143. auto originalNumAtts = attributes.size();
  144. text += other.text;
  145. attributes.addArray (other.attributes);
  146. for (auto i = originalNumAtts; i < attributes.size(); ++i)
  147. attributes.getReference (i).range += originalLength;
  148. mergeAdjacentRanges (attributes);
  149. }
  150. void AttributedString::clear()
  151. {
  152. text.clear();
  153. attributes.clear();
  154. }
  155. void AttributedString::setJustification (Justification newJustification) noexcept
  156. {
  157. justification = newJustification;
  158. }
  159. void AttributedString::setWordWrap (WordWrap newWordWrap) noexcept
  160. {
  161. wordWrap = newWordWrap;
  162. }
  163. void AttributedString::setReadingDirection (ReadingDirection newReadingDirection) noexcept
  164. {
  165. readingDirection = newReadingDirection;
  166. }
  167. void AttributedString::setLineSpacing (const float newLineSpacing) noexcept
  168. {
  169. lineSpacing = newLineSpacing;
  170. }
  171. void AttributedString::setColour (Range<int> range, Colour colour)
  172. {
  173. applyFontAndColour (attributes, range, nullptr, &colour);
  174. }
  175. void AttributedString::setFont (Range<int> range, const Font& font)
  176. {
  177. applyFontAndColour (attributes, range, &font, nullptr);
  178. }
  179. void AttributedString::setColour (Colour colour)
  180. {
  181. setColour ({ 0, getLength (attributes) }, colour);
  182. }
  183. void AttributedString::setFont (const Font& font)
  184. {
  185. setFont ({ 0, getLength (attributes) }, font);
  186. }
  187. void AttributedString::draw (Graphics& g, const Rectangle<float>& area) const
  188. {
  189. if (text.isNotEmpty() && g.clipRegionIntersects (area.getSmallestIntegerContainer()))
  190. {
  191. jassert (text.length() == getLength (attributes));
  192. if (! g.getInternalContext().drawTextLayout (*this, area))
  193. {
  194. TextLayout layout;
  195. layout.createLayout (*this, area.getWidth());
  196. layout.draw (g, area);
  197. }
  198. }
  199. }
  200. } // namespace juce