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.

354 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. namespace
  18. {
  19. int getLength (const Array<AttributedString::Attribute>& atts) noexcept
  20. {
  21. return atts.size() != 0 ? atts.getReference (atts.size() - 1).range.getEnd() : 0;
  22. }
  23. void splitAttributeRanges (Array<AttributedString::Attribute>& atts, int position)
  24. {
  25. for (int i = atts.size(); --i >= 0;)
  26. {
  27. const AttributedString::Attribute& att = atts.getReference (i);
  28. const int offset = position - att.range.getStart();
  29. if (offset >= 0)
  30. {
  31. if (offset > 0 && position < att.range.getEnd())
  32. {
  33. atts.insert (i + 1, att);
  34. atts.getReference (i).range.setEnd (position);
  35. atts.getReference (i + 1).range.setStart (position);
  36. }
  37. break;
  38. }
  39. }
  40. }
  41. Range<int> splitAttributeRanges (Array<AttributedString::Attribute>& atts, Range<int> newRange)
  42. {
  43. newRange = newRange.getIntersectionWith (Range<int> (0, getLength (atts)));
  44. if (! newRange.isEmpty())
  45. {
  46. splitAttributeRanges (atts, newRange.getStart());
  47. splitAttributeRanges (atts, newRange.getEnd());
  48. }
  49. return newRange;
  50. }
  51. void mergeAdjacentRanges (Array<AttributedString::Attribute>& atts)
  52. {
  53. for (int i = atts.size() - 1; --i >= 0;)
  54. {
  55. AttributedString::Attribute& a1 = atts.getReference (i);
  56. AttributedString::Attribute& a2 = atts.getReference (i + 1);
  57. if (a1.colour == a2.colour && a1.font == a2.font)
  58. {
  59. a1.range.setEnd (a2.range.getEnd());
  60. atts.remove (i + 1);
  61. if (i < atts.size() - 1)
  62. ++i;
  63. }
  64. }
  65. }
  66. void appendRange (Array<AttributedString::Attribute>& atts,
  67. int length, const Font* f, const Colour* c)
  68. {
  69. if (atts.size() == 0)
  70. {
  71. atts.add (AttributedString::Attribute (Range<int> (0, length),
  72. f != nullptr ? *f : Font(),
  73. c != nullptr ? *c : Colour (0xff000000)));
  74. }
  75. else
  76. {
  77. const int start = getLength (atts);
  78. atts.add (AttributedString::Attribute (Range<int> (start, start + length),
  79. f != nullptr ? *f : atts.getReference (atts.size() - 1).font,
  80. c != nullptr ? *c : atts.getReference (atts.size() - 1).colour));
  81. mergeAdjacentRanges (atts);
  82. }
  83. }
  84. void applyFontAndColour (Array<AttributedString::Attribute>& atts,
  85. Range<int> range, const Font* f, const Colour* c)
  86. {
  87. range = splitAttributeRanges (atts, range);
  88. for (int i = 0; i < atts.size(); ++i)
  89. {
  90. AttributedString::Attribute& att = atts.getReference (i);
  91. if (range.getStart() < att.range.getEnd())
  92. {
  93. if (range.getEnd() <= att.range.getStart())
  94. break;
  95. if (c != nullptr) att.colour = *c;
  96. if (f != nullptr) att.font = *f;
  97. }
  98. }
  99. mergeAdjacentRanges (atts);
  100. }
  101. void truncate (Array<AttributedString::Attribute>& atts, int newLength)
  102. {
  103. splitAttributeRanges (atts, newLength);
  104. for (int i = atts.size(); --i >= 0;)
  105. if (atts.getReference (i).range.getStart() >= newLength)
  106. atts.remove (i);
  107. }
  108. }
  109. //==============================================================================
  110. AttributedString::Attribute::Attribute() noexcept : colour (0xff000000) {}
  111. AttributedString::Attribute::~Attribute() noexcept {}
  112. #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
  113. AttributedString::Attribute::Attribute (Attribute&& other) noexcept
  114. : range (other.range),
  115. font (static_cast<Font&&> (other.font)),
  116. colour (other.colour)
  117. {
  118. }
  119. AttributedString::Attribute& AttributedString::Attribute::operator= (Attribute&& other) noexcept
  120. {
  121. range = other.range;
  122. font = static_cast<Font&&> (other.font);
  123. colour = other.colour;
  124. return *this;
  125. }
  126. #endif
  127. AttributedString::Attribute::Attribute (const Attribute& other) noexcept
  128. : range (other.range),
  129. font (other.font),
  130. colour (other.colour)
  131. {
  132. }
  133. AttributedString::Attribute& AttributedString::Attribute::operator= (const Attribute& other) noexcept
  134. {
  135. range = other.range;
  136. font = other.font;
  137. colour = other.colour;
  138. return *this;
  139. }
  140. AttributedString::Attribute::Attribute (Range<int> r, const Font& f, Colour c) noexcept
  141. : range (r), font (f), colour (c)
  142. {
  143. }
  144. //==============================================================================
  145. AttributedString::AttributedString()
  146. : lineSpacing (0.0f),
  147. justification (Justification::left),
  148. wordWrap (AttributedString::byWord),
  149. readingDirection (AttributedString::natural)
  150. {
  151. }
  152. AttributedString::AttributedString (const String& newString)
  153. : lineSpacing (0.0f),
  154. justification (Justification::left),
  155. wordWrap (AttributedString::byWord),
  156. readingDirection (AttributedString::natural)
  157. {
  158. setText (newString);
  159. }
  160. AttributedString::AttributedString (const AttributedString& other)
  161. : text (other.text),
  162. lineSpacing (other.lineSpacing),
  163. justification (other.justification),
  164. wordWrap (other.wordWrap),
  165. readingDirection (other.readingDirection),
  166. attributes (other.attributes)
  167. {
  168. }
  169. AttributedString& AttributedString::operator= (const AttributedString& other)
  170. {
  171. if (this != &other)
  172. {
  173. text = other.text;
  174. lineSpacing = other.lineSpacing;
  175. justification = other.justification;
  176. wordWrap = other.wordWrap;
  177. readingDirection = other.readingDirection;
  178. attributes = other.attributes;
  179. }
  180. return *this;
  181. }
  182. #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
  183. AttributedString::AttributedString (AttributedString&& other) noexcept
  184. : text (static_cast<String&&> (other.text)),
  185. lineSpacing (other.lineSpacing),
  186. justification (other.justification),
  187. wordWrap (other.wordWrap),
  188. readingDirection (other.readingDirection),
  189. attributes (static_cast<Array<Attribute>&&> (other.attributes))
  190. {
  191. }
  192. AttributedString& AttributedString::operator= (AttributedString&& other) noexcept
  193. {
  194. text = static_cast<String&&> (other.text);
  195. lineSpacing = other.lineSpacing;
  196. justification = other.justification;
  197. wordWrap = other.wordWrap;
  198. readingDirection = other.readingDirection;
  199. attributes = static_cast<Array<Attribute>&&> (other.attributes);
  200. return *this;
  201. }
  202. #endif
  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. }