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_GlyphArrangement.h 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software 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. #ifndef JUCE_GLYPHARRANGEMENT_H_INCLUDED
  18. #define JUCE_GLYPHARRANGEMENT_H_INCLUDED
  19. //==============================================================================
  20. /**
  21. A glyph from a particular font, with a particular size, style,
  22. typeface and position.
  23. You should rarely need to use this class directly - for most purposes, the
  24. GlyphArrangement class will do what you need for text layout.
  25. @see GlyphArrangement, Font
  26. */
  27. class JUCE_API PositionedGlyph
  28. {
  29. public:
  30. //==============================================================================
  31. PositionedGlyph() noexcept;
  32. PositionedGlyph (const Font& font, juce_wchar character, int glyphNumber,
  33. float anchorX, float baselineY, float width, bool isWhitespace);
  34. PositionedGlyph (const PositionedGlyph&);
  35. PositionedGlyph& operator= (const PositionedGlyph&);
  36. ~PositionedGlyph();
  37. /** Returns the character the glyph represents. */
  38. juce_wchar getCharacter() const noexcept { return character; }
  39. /** Checks whether the glyph is actually empty. */
  40. bool isWhitespace() const noexcept { return whitespace; }
  41. /** Returns the position of the glyph's left-hand edge. */
  42. float getLeft() const noexcept { return x; }
  43. /** Returns the position of the glyph's right-hand edge. */
  44. float getRight() const noexcept { return x + w; }
  45. /** Returns the y position of the glyph's baseline. */
  46. float getBaselineY() const noexcept { return y; }
  47. /** Returns the y position of the top of the glyph. */
  48. float getTop() const { return y - font.getAscent(); }
  49. /** Returns the y position of the bottom of the glyph. */
  50. float getBottom() const { return y + font.getDescent(); }
  51. /** Returns the bounds of the glyph. */
  52. Rectangle<float> getBounds() const { return Rectangle<float> (x, getTop(), w, font.getHeight()); }
  53. //==============================================================================
  54. /** Shifts the glyph's position by a relative amount. */
  55. void moveBy (float deltaX, float deltaY);
  56. //==============================================================================
  57. /** Draws the glyph into a graphics context. */
  58. void draw (const Graphics& g) const;
  59. /** Draws the glyph into a graphics context, with an extra transform applied to it. */
  60. void draw (const Graphics& g, const AffineTransform& transform) const;
  61. /** Returns the path for this glyph.
  62. @param path the glyph's outline will be appended to this path
  63. */
  64. void createPath (Path& path) const;
  65. /** Checks to see if a point lies within this glyph. */
  66. bool hitTest (float x, float y) const;
  67. private:
  68. //==============================================================================
  69. friend class GlyphArrangement;
  70. Font font;
  71. juce_wchar character;
  72. int glyph;
  73. float x, y, w;
  74. bool whitespace;
  75. JUCE_LEAK_DETECTOR (PositionedGlyph)
  76. };
  77. //==============================================================================
  78. /**
  79. A set of glyphs, each with a position.
  80. You can create a GlyphArrangement, text to it and then draw it onto a
  81. graphics context. It's used internally by the text methods in the
  82. Graphics class, but can be used directly if more control is needed.
  83. @see Font, PositionedGlyph
  84. */
  85. class JUCE_API GlyphArrangement
  86. {
  87. public:
  88. //==============================================================================
  89. /** Creates an empty arrangement. */
  90. GlyphArrangement();
  91. /** Takes a copy of another arrangement. */
  92. GlyphArrangement (const GlyphArrangement&);
  93. /** Copies another arrangement onto this one.
  94. To add another arrangement without clearing this one, use addGlyphArrangement().
  95. */
  96. GlyphArrangement& operator= (const GlyphArrangement&);
  97. /** Destructor. */
  98. ~GlyphArrangement();
  99. //==============================================================================
  100. /** Returns the total number of glyphs in the arrangement. */
  101. int getNumGlyphs() const noexcept { return glyphs.size(); }
  102. /** Returns one of the glyphs from the arrangement.
  103. @param index the glyph's index, from 0 to (getNumGlyphs() - 1). Be
  104. careful not to pass an out-of-range index here, as it
  105. doesn't do any bounds-checking.
  106. */
  107. PositionedGlyph& getGlyph (int index) const noexcept;
  108. //==============================================================================
  109. /** Clears all text from the arrangement and resets it. */
  110. void clear();
  111. /** Appends a line of text to the arrangement.
  112. This will add the text as a single line, where x is the left-hand edge of the
  113. first character, and y is the position for the text's baseline.
  114. If the text contains new-lines or carriage-returns, this will ignore them - use
  115. addJustifiedText() to add multi-line arrangements.
  116. */
  117. void addLineOfText (const Font& font,
  118. const String& text,
  119. float x, float y);
  120. /** Adds a line of text, truncating it if it's wider than a specified size.
  121. This is the same as addLineOfText(), but if the line's width exceeds the value
  122. specified in maxWidthPixels, it will be truncated using either ellipsis (i.e. dots: "..."),
  123. if useEllipsis is true, or if this is false, it will just drop any subsequent characters.
  124. */
  125. void addCurtailedLineOfText (const Font& font,
  126. const String& text,
  127. float x, float y,
  128. float maxWidthPixels,
  129. bool useEllipsis);
  130. /** Adds some multi-line text, breaking lines at word-boundaries if they are too wide.
  131. This will add text to the arrangement, breaking it into new lines either where there
  132. is a new-line or carriage-return character in the text, or where a line's width
  133. exceeds the value set in maxLineWidth.
  134. Each line that is added will be laid out using the flags set in horizontalLayout, so
  135. the lines can be left- or right-justified, or centred horizontally in the space
  136. between x and (x + maxLineWidth).
  137. The y coordinate is the position of the baseline of the first line of text - subsequent
  138. lines will be placed below it, separated by a distance of font.getHeight().
  139. */
  140. void addJustifiedText (const Font& font,
  141. const String& text,
  142. float x, float y,
  143. float maxLineWidth,
  144. Justification horizontalLayout);
  145. /** Tries to fit some text withing a given space.
  146. This does its best to make the given text readable within the specified rectangle,
  147. so it useful for labelling things.
  148. If the text is too big, it'll be squashed horizontally or broken over multiple lines
  149. if the maximumLinesToUse value allows this. If the text just won't fit into the space,
  150. it'll cram as much as possible in there, and put some ellipsis at the end to show that
  151. it's been truncated.
  152. A Justification parameter lets you specify how the text is laid out within the rectangle,
  153. both horizontally and vertically.
  154. @see Graphics::drawFittedText
  155. */
  156. void addFittedText (const Font& font,
  157. const String& text,
  158. float x, float y, float width, float height,
  159. Justification layout,
  160. int maximumLinesToUse,
  161. float minimumHorizontalScale = 0.7f);
  162. /** Appends another glyph arrangement to this one. */
  163. void addGlyphArrangement (const GlyphArrangement&);
  164. /** Appends a custom glyph to the arrangement. */
  165. void addGlyph (const PositionedGlyph&);
  166. //==============================================================================
  167. /** Draws this glyph arrangement to a graphics context.
  168. This uses cached bitmaps so is much faster than the draw (Graphics&, const AffineTransform&)
  169. method, which renders the glyphs as filled vectors.
  170. */
  171. void draw (const Graphics&) const;
  172. /** Draws this glyph arrangement to a graphics context.
  173. This renders the paths as filled vectors, so is far slower than the draw (Graphics&)
  174. method for non-transformed arrangements.
  175. */
  176. void draw (const Graphics&, const AffineTransform&) const;
  177. /** Converts the set of glyphs into a path.
  178. @param path the glyphs' outlines will be appended to this path
  179. */
  180. void createPath (Path& path) const;
  181. /** Looks for a glyph that contains the given coordinate.
  182. @returns the index of the glyph, or -1 if none were found.
  183. */
  184. int findGlyphIndexAt (float x, float y) const;
  185. //==============================================================================
  186. /** Finds the smallest rectangle that will enclose a subset of the glyphs.
  187. @param startIndex the first glyph to test
  188. @param numGlyphs the number of glyphs to include; if this is < 0, all glyphs after
  189. startIndex will be included
  190. @param includeWhitespace if true, the extent of any whitespace characters will also
  191. be taken into account
  192. */
  193. Rectangle<float> getBoundingBox (int startIndex, int numGlyphs, bool includeWhitespace) const;
  194. /** Shifts a set of glyphs by a given amount.
  195. @param startIndex the first glyph to transform
  196. @param numGlyphs the number of glyphs to move; if this is < 0, all glyphs after
  197. startIndex will be used
  198. @param deltaX the amount to add to their x-positions
  199. @param deltaY the amount to add to their y-positions
  200. */
  201. void moveRangeOfGlyphs (int startIndex, int numGlyphs,
  202. float deltaX, float deltaY);
  203. /** Removes a set of glyphs from the arrangement.
  204. @param startIndex the first glyph to remove
  205. @param numGlyphs the number of glyphs to remove; if this is < 0, all glyphs after
  206. startIndex will be deleted
  207. */
  208. void removeRangeOfGlyphs (int startIndex, int numGlyphs);
  209. /** Expands or compresses a set of glyphs horizontally.
  210. @param startIndex the first glyph to transform
  211. @param numGlyphs the number of glyphs to stretch; if this is < 0, all glyphs after
  212. startIndex will be used
  213. @param horizontalScaleFactor how much to scale their horizontal width by
  214. */
  215. void stretchRangeOfGlyphs (int startIndex, int numGlyphs,
  216. float horizontalScaleFactor);
  217. /** Justifies a set of glyphs within a given space.
  218. This moves the glyphs as a block so that the whole thing is located within the
  219. given rectangle with the specified layout.
  220. If the Justification::horizontallyJustified flag is specified, each line will
  221. be stretched out to fill the specified width.
  222. */
  223. void justifyGlyphs (int startIndex, int numGlyphs,
  224. float x, float y, float width, float height,
  225. Justification justification);
  226. private:
  227. //==============================================================================
  228. Array <PositionedGlyph> glyphs;
  229. int insertEllipsis (const Font&, float maxXPos, int startIndex, int endIndex);
  230. int fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font&,
  231. Justification, float minimumHorizontalScale);
  232. void spreadOutLine (int start, int numGlyphs, float targetWidth);
  233. void drawGlyphUnderline (const Graphics&, const PositionedGlyph&, int, const AffineTransform&) const;
  234. JUCE_LEAK_DETECTOR (GlyphArrangement)
  235. };
  236. #endif // JUCE_GLYPHARRANGEMENT_H_INCLUDED