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.

juce_AttributedString.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. namespace
  22. {
  23. int getLength (const Array<AttributedString::Attribute>& atts) noexcept
  24. {
  25. return atts.size() != 0 ? atts.getReference (atts.size() - 1).range.getEnd() : 0;
  26. }
  27. void splitAttributeRanges (Array<AttributedString::Attribute>& atts, int position)
  28. {
  29. for (int i = atts.size(); --i >= 0;)
  30. {
  31. const AttributedString::Attribute& att = atts.getReference (i);
  32. const int offset = position - att.range.getStart();
  33. if (offset >= 0)
  34. {
  35. if (offset > 0 && position < att.range.getEnd())
  36. {
  37. atts.insert (i + 1, att);
  38. atts.getReference (i).range.setEnd (position);
  39. atts.getReference (i + 1).range.setStart (position);
  40. }
  41. break;
  42. }
  43. }
  44. }
  45. Range<int> splitAttributeRanges (Array<AttributedString::Attribute>& atts, Range<int> newRange)
  46. {
  47. newRange = newRange.getIntersectionWith (Range<int> (0, getLength (atts)));
  48. if (! newRange.isEmpty())
  49. {
  50. splitAttributeRanges (atts, newRange.getStart());
  51. splitAttributeRanges (atts, newRange.getEnd());
  52. }
  53. return newRange;
  54. }
  55. void mergeAdjacentRanges (Array<AttributedString::Attribute>& atts)
  56. {
  57. for (int i = atts.size() - 1; --i >= 0;)
  58. {
  59. AttributedString::Attribute& a1 = atts.getReference (i);
  60. AttributedString::Attribute& a2 = atts.getReference (i + 1);
  61. if (a1.colour == a2.colour && a1.font == a2.font)
  62. {
  63. a1.range.setEnd (a2.range.getEnd());
  64. atts.remove (i + 1);
  65. if (i < atts.size() - 1)
  66. ++i;
  67. }
  68. }
  69. }
  70. void appendRange (Array<AttributedString::Attribute>& atts,
  71. int length, const Font* f, const Colour* c)
  72. {
  73. if (atts.size() == 0)
  74. {
  75. atts.add (AttributedString::Attribute (Range<int> (0, length),
  76. f != nullptr ? *f : Font(),
  77. c != nullptr ? *c : Colour (0xff000000)));
  78. }
  79. else
  80. {
  81. const int start = getLength (atts);
  82. atts.add (AttributedString::Attribute (Range<int> (start, start + length),
  83. f != nullptr ? *f : atts.getReference (atts.size() - 1).font,
  84. c != nullptr ? *c : atts.getReference (atts.size() - 1).colour));
  85. mergeAdjacentRanges (atts);
  86. }
  87. }
  88. void applyFontAndColour (Array<AttributedString::Attribute>& atts,
  89. Range<int> range, const Font* f, const Colour* c)
  90. {
  91. range = splitAttributeRanges (atts, range);
  92. for (int i = 0; i < atts.size(); ++i)
  93. {
  94. AttributedString::Attribute& att = atts.getReference (i);
  95. if (range.getStart() < att.range.getEnd())
  96. {
  97. if (range.getEnd() <= att.range.getStart())
  98. break;
  99. if (c != nullptr) att.colour = *c;
  100. if (f != nullptr) att.font = *f;
  101. }
  102. }
  103. mergeAdjacentRanges (atts);
  104. }
  105. void truncate (Array<AttributedString::Attribute>& atts, int newLength)
  106. {
  107. splitAttributeRanges (atts, newLength);
  108. for (int i = atts.size(); --i >= 0;)
  109. if (atts.getReference (i).range.getStart() >= newLength)
  110. atts.remove (i);
  111. }
  112. }
  113. //==============================================================================
  114. AttributedString::Attribute::Attribute() noexcept : colour (0xff000000) {}
  115. AttributedString::Attribute::~Attribute() noexcept {}
  116. AttributedString::Attribute::Attribute (Attribute&& other) noexcept
  117. : range (other.range),
  118. font (static_cast<Font&&> (other.font)),
  119. colour (other.colour)
  120. {
  121. }
  122. AttributedString::Attribute& AttributedString::Attribute::operator= (Attribute&& other) noexcept
  123. {
  124. range = other.range;
  125. font = static_cast<Font&&> (other.font);
  126. colour = other.colour;
  127. return *this;
  128. }
  129. AttributedString::Attribute::Attribute (const Attribute& other) noexcept
  130. : range (other.range),
  131. font (other.font),
  132. colour (other.colour)
  133. {
  134. }
  135. AttributedString::Attribute& AttributedString::Attribute::operator= (const Attribute& other) noexcept
  136. {
  137. range = other.range;
  138. font = other.font;
  139. colour = other.colour;
  140. return *this;
  141. }
  142. AttributedString::Attribute::Attribute (Range<int> r, const Font& f, Colour c) noexcept
  143. : range (r), font (f), colour (c)
  144. {
  145. }
  146. //==============================================================================
  147. AttributedString::AttributedString()
  148. : lineSpacing (0.0f),
  149. justification (Justification::left),
  150. wordWrap (AttributedString::byWord),
  151. readingDirection (AttributedString::natural)
  152. {
  153. }
  154. AttributedString::AttributedString (const String& newString)
  155. : lineSpacing (0.0f),
  156. justification (Justification::left),
  157. wordWrap (AttributedString::byWord),
  158. readingDirection (AttributedString::natural)
  159. {
  160. setText (newString);
  161. }
  162. AttributedString::AttributedString (const AttributedString& other)
  163. : text (other.text),
  164. lineSpacing (other.lineSpacing),
  165. justification (other.justification),
  166. wordWrap (other.wordWrap),
  167. readingDirection (other.readingDirection),
  168. attributes (other.attributes)
  169. {
  170. }
  171. AttributedString& AttributedString::operator= (const AttributedString& other)
  172. {
  173. if (this != &other)
  174. {
  175. text = other.text;
  176. lineSpacing = other.lineSpacing;
  177. justification = other.justification;
  178. wordWrap = other.wordWrap;
  179. readingDirection = other.readingDirection;
  180. attributes = other.attributes;
  181. }
  182. return *this;
  183. }
  184. AttributedString::AttributedString (AttributedString&& other) noexcept
  185. : text (static_cast<String&&> (other.text)),
  186. lineSpacing (other.lineSpacing),
  187. justification (other.justification),
  188. wordWrap (other.wordWrap),
  189. readingDirection (other.readingDirection),
  190. attributes (static_cast<Array<Attribute>&&> (other.attributes))
  191. {
  192. }
  193. AttributedString& AttributedString::operator= (AttributedString&& other) noexcept
  194. {
  195. text = static_cast<String&&> (other.text);
  196. lineSpacing = other.lineSpacing;
  197. justification = other.justification;
  198. wordWrap = other.wordWrap;
  199. readingDirection = other.readingDirection;
  200. attributes = static_cast<Array<Attribute>&&> (other.attributes);
  201. return *this;
  202. }
  203. AttributedString::~AttributedString() noexcept {}
  204. void AttributedString::setText (const String& newText)
  205. {
  206. const int newLength = newText.length();
  207. const int oldLength = getLength (attributes);
  208. if (newLength > oldLength)
  209. appendRange (attributes, newLength - oldLength, nullptr, nullptr);
  210. else if (newLength < oldLength)
  211. truncate (attributes, newLength);
  212. text = newText;
  213. }
  214. void AttributedString::append (const String& textToAppend)
  215. {
  216. text += textToAppend;
  217. appendRange (attributes, textToAppend.length(), nullptr, nullptr);
  218. }
  219. void AttributedString::append (const String& textToAppend, const Font& font)
  220. {
  221. text += textToAppend;
  222. appendRange (attributes, textToAppend.length(), &font, nullptr);
  223. }
  224. void AttributedString::append (const String& textToAppend, Colour colour)
  225. {
  226. text += textToAppend;
  227. appendRange (attributes, textToAppend.length(), nullptr, &colour);
  228. }
  229. void AttributedString::append (const String& textToAppend, const Font& font, Colour colour)
  230. {
  231. text += textToAppend;
  232. appendRange (attributes, textToAppend.length(), &font, &colour);
  233. }
  234. void AttributedString::append (const AttributedString& other)
  235. {
  236. const int originalLength = getLength (attributes);
  237. const int originalNumAtts = attributes.size();
  238. text += other.text;
  239. attributes.addArray (other.attributes);
  240. for (int i = originalNumAtts; i < attributes.size(); ++i)
  241. attributes.getReference (i).range += originalLength;
  242. mergeAdjacentRanges (attributes);
  243. }
  244. void AttributedString::clear()
  245. {
  246. text.clear();
  247. attributes.clear();
  248. }
  249. void AttributedString::setJustification (Justification newJustification) noexcept
  250. {
  251. justification = newJustification;
  252. }
  253. void AttributedString::setWordWrap (WordWrap newWordWrap) noexcept
  254. {
  255. wordWrap = newWordWrap;
  256. }
  257. void AttributedString::setReadingDirection (ReadingDirection newReadingDirection) noexcept
  258. {
  259. readingDirection = newReadingDirection;
  260. }
  261. void AttributedString::setLineSpacing (const float newLineSpacing) noexcept
  262. {
  263. lineSpacing = newLineSpacing;
  264. }
  265. void AttributedString::setColour (Range<int> range, Colour colour)
  266. {
  267. applyFontAndColour (attributes, range, nullptr, &colour);
  268. }
  269. void AttributedString::setFont (Range<int> range, const Font& font)
  270. {
  271. applyFontAndColour (attributes, range, &font, nullptr);
  272. }
  273. void AttributedString::setColour (Colour colour)
  274. {
  275. setColour (Range<int> (0, getLength (attributes)), colour);
  276. }
  277. void AttributedString::setFont (const Font& font)
  278. {
  279. setFont (Range<int> (0, getLength (attributes)), font);
  280. }
  281. void AttributedString::draw (Graphics& g, const Rectangle<float>& area) const
  282. {
  283. if (text.isNotEmpty() && g.clipRegionIntersects (area.getSmallestIntegerContainer()))
  284. {
  285. jassert (text.length() == getLength (attributes));
  286. if (! g.getInternalContext().drawTextLayout (*this, area))
  287. {
  288. TextLayout layout;
  289. layout.createLayout (*this, area.getWidth());
  290. layout.draw (g, area);
  291. }
  292. }
  293. }
  294. } // namespace juce