LMMS
Loading...
Searching...
No Matches
juce_GlyphArrangement.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
29static constexpr bool isNonBreakingSpace (const juce_wchar c)
30{
31 return c == 0x00a0
32 || c == 0x2007
33 || c == 0x202f
34 || c == 0x2060;
35}
36
38 : character (0), glyph (0), x (0), y (0), w (0), whitespace (false)
39{
40}
41
42PositionedGlyph::PositionedGlyph (const Font& font_, juce_wchar character_, int glyphNumber,
43 float anchorX, float baselineY, float width, bool whitespace_)
44 : font (font_), character (character_), glyph (glyphNumber),
45 x (anchorX), y (baselineY), w (width), whitespace (whitespace_)
46{
47}
48
49static void drawGlyphWithFont (Graphics& g, int glyph, const Font& font, AffineTransform t)
50{
51 auto& context = g.getInternalContext();
52 context.setFont (font);
53 context.drawGlyph (glyph, t);
54}
55
61
63{
64 if (! isWhitespace())
65 drawGlyphWithFont (g, glyph, font, AffineTransform::translation (x, y).followedBy (transform));
66}
67
69{
70 if (! isWhitespace())
71 {
72 if (auto t = font.getTypefacePtr())
73 {
74 Path p;
75 t->getOutlineForGlyph (glyph, p);
76
77 path.addPath (p, AffineTransform::scale (font.getHeight() * font.getHorizontalScale(), font.getHeight())
78 .translated (x, y));
79 }
80 }
81}
82
83bool PositionedGlyph::hitTest (float px, float py) const
84{
85 if (getBounds().contains (px, py) && ! isWhitespace())
86 {
87 if (auto t = font.getTypefacePtr())
88 {
89 Path p;
90 t->getOutlineForGlyph (glyph, p);
91
93 .scaled (1.0f / (font.getHeight() * font.getHorizontalScale()), 1.0f / font.getHeight())
94 .transformPoint (px, py);
95
96 return p.contains (px, py);
97 }
98 }
99
100 return false;
101}
102
103void PositionedGlyph::moveBy (float deltaX, float deltaY)
104{
105 x += deltaX;
106 y += deltaY;
107}
108
109
110//==============================================================================
112{
113 glyphs.ensureStorageAllocated (128);
114}
115
116//==============================================================================
118{
119 glyphs.clear();
120}
121
123{
124 return glyphs.getReference (index);
125}
126
127//==============================================================================
129{
130 glyphs.addArray (other.glyphs);
131}
132
134{
135 glyphs.add (glyph);
136}
137
138void GlyphArrangement::removeRangeOfGlyphs (int startIndex, int num)
139{
140 glyphs.removeRange (startIndex, num < 0 ? glyphs.size() : num);
141}
142
143//==============================================================================
144void GlyphArrangement::addLineOfText (const Font& font, const String& text, float xOffset, float yOffset)
145{
146 addCurtailedLineOfText (font, text, xOffset, yOffset, 1.0e10f, false);
147}
148
150 float xOffset, float yOffset,
151 float maxWidthPixels, bool useEllipsis)
152{
153 if (text.isNotEmpty())
154 {
155 Array<int> newGlyphs;
156 Array<float> xOffsets;
157 font.getGlyphPositions (text, newGlyphs, xOffsets);
158 auto textLen = newGlyphs.size();
159 glyphs.ensureStorageAllocated (glyphs.size() + textLen);
160
161 auto t = text.getCharPointer();
162
163 for (int i = 0; i < textLen; ++i)
164 {
165 auto nextX = xOffsets.getUnchecked (i + 1);
166
167 if (nextX > maxWidthPixels + 1.0f)
168 {
169 // curtail the string if it's too wide..
170 if (useEllipsis && textLen > 3 && glyphs.size() >= 3)
171 insertEllipsis (font, xOffset + maxWidthPixels, 0, glyphs.size());
172
173 break;
174 }
175
176 auto thisX = xOffsets.getUnchecked (i);
177 auto isWhitespace = isNonBreakingSpace (*t) || t.isWhitespace();
178
179 glyphs.add (PositionedGlyph (font, t.getAndAdvance(),
180 newGlyphs.getUnchecked(i),
181 xOffset + thisX, yOffset,
182 nextX - thisX, isWhitespace));
183 }
184 }
185}
186
187int GlyphArrangement::insertEllipsis (const Font& font, float maxXPos, int startIndex, int endIndex)
188{
189 int numDeleted = 0;
190
191 if (! glyphs.isEmpty())
192 {
193 Array<int> dotGlyphs;
194 Array<float> dotXs;
195 font.getGlyphPositions ("..", dotGlyphs, dotXs);
196
197 auto dx = dotXs[1];
198 float xOffset = 0.0f, yOffset = 0.0f;
199
200 while (endIndex > startIndex)
201 {
202 auto& pg = glyphs.getReference (--endIndex);
203 xOffset = pg.x;
204 yOffset = pg.y;
205
206 glyphs.remove (endIndex);
207 ++numDeleted;
208
209 if (xOffset + dx * 3 <= maxXPos)
210 break;
211 }
212
213 for (int i = 3; --i >= 0;)
214 {
215 glyphs.insert (endIndex++, PositionedGlyph (font, '.', dotGlyphs.getFirst(),
216 xOffset, yOffset, dx, false));
217 --numDeleted;
218 xOffset += dx;
219
220 if (xOffset > maxXPos)
221 break;
222 }
223 }
224
225 return numDeleted;
226}
227
229 float x, float y, float maxLineWidth,
230 Justification horizontalLayout,
231 float leading)
232{
233 auto lineStartIndex = glyphs.size();
234 addLineOfText (font, text, x, y);
235
236 auto originalY = y;
237
238 while (lineStartIndex < glyphs.size())
239 {
240 int i = lineStartIndex;
241
242 if (glyphs.getReference(i).getCharacter() != '\n'
243 && glyphs.getReference(i).getCharacter() != '\r')
244 ++i;
245
246 auto lineMaxX = glyphs.getReference (lineStartIndex).getLeft() + maxLineWidth;
247 int lastWordBreakIndex = -1;
248
249 while (i < glyphs.size())
250 {
251 auto& pg = glyphs.getReference (i);
252 auto c = pg.getCharacter();
253
254 if (c == '\r' || c == '\n')
255 {
256 ++i;
257
258 if (c == '\r' && i < glyphs.size()
259 && glyphs.getReference(i).getCharacter() == '\n')
260 ++i;
261
262 break;
263 }
264
265 if (pg.isWhitespace())
266 {
267 lastWordBreakIndex = i + 1;
268 }
269 else if (pg.getRight() - 0.0001f >= lineMaxX)
270 {
271 if (lastWordBreakIndex >= 0)
272 i = lastWordBreakIndex;
273
274 break;
275 }
276
277 ++i;
278 }
279
280 auto currentLineStartX = glyphs.getReference (lineStartIndex).getLeft();
281 auto currentLineEndX = currentLineStartX;
282
283 for (int j = i; --j >= lineStartIndex;)
284 {
285 if (! glyphs.getReference (j).isWhitespace())
286 {
287 currentLineEndX = glyphs.getReference (j).getRight();
288 break;
289 }
290 }
291
292 float deltaX = 0.0f;
293
294 if (horizontalLayout.testFlags (Justification::horizontallyJustified))
295 spreadOutLine (lineStartIndex, i - lineStartIndex, maxLineWidth);
296 else if (horizontalLayout.testFlags (Justification::horizontallyCentred))
297 deltaX = (maxLineWidth - (currentLineEndX - currentLineStartX)) * 0.5f;
298 else if (horizontalLayout.testFlags (Justification::right))
299 deltaX = maxLineWidth - (currentLineEndX - currentLineStartX);
300
301 moveRangeOfGlyphs (lineStartIndex, i - lineStartIndex,
302 x + deltaX - currentLineStartX, y - originalY);
303
304 lineStartIndex = i;
305
306 y += font.getHeight() + leading;
307 }
308}
309
311 float x, float y, float width, float height,
312 Justification layout, int maximumLines,
313 float minimumHorizontalScale)
314{
315 if (minimumHorizontalScale == 0.0f)
316 minimumHorizontalScale = Font::getDefaultMinimumHorizontalScaleFactor();
317
318 // doesn't make much sense if this is outside a sensible range of 0.5 to 1.0
319 jassert (minimumHorizontalScale > 0 && minimumHorizontalScale <= 1.0f);
320
321 if (text.containsAnyOf ("\r\n"))
322 {
323 addLinesWithLineBreaks (text, f, x, y, width, height, layout);
324 }
325 else
326 {
327 auto startIndex = glyphs.size();
328 auto trimmed = text.trim();
329 addLineOfText (f, trimmed, x, y);
330 auto numGlyphs = glyphs.size() - startIndex;
331
332 if (numGlyphs > 0)
333 {
334 auto lineWidth = glyphs.getReference (glyphs.size() - 1).getRight()
335 - glyphs.getReference (startIndex).getLeft();
336
337 if (lineWidth > 0)
338 {
339 if (lineWidth * minimumHorizontalScale < width)
340 {
341 if (lineWidth > width)
342 stretchRangeOfGlyphs (startIndex, numGlyphs, width / lineWidth);
343
344 justifyGlyphs (startIndex, numGlyphs, x, y, width, height, layout);
345 }
346 else if (maximumLines <= 1)
347 {
348 fitLineIntoSpace (startIndex, numGlyphs, x, y, width, height,
349 f, layout, minimumHorizontalScale);
350 }
351 else
352 {
353 splitLines (trimmed, f, startIndex, x, y, width, height,
354 maximumLines, lineWidth, layout, minimumHorizontalScale);
355 }
356 }
357 }
358 }
359}
360
361//==============================================================================
362void GlyphArrangement::moveRangeOfGlyphs (int startIndex, int num, const float dx, const float dy)
363{
364 jassert (startIndex >= 0);
365
366 if (dx != 0.0f || dy != 0.0f)
367 {
368 if (num < 0 || startIndex + num > glyphs.size())
369 num = glyphs.size() - startIndex;
370
371 while (--num >= 0)
372 glyphs.getReference (startIndex++).moveBy (dx, dy);
373 }
374}
375
377 float x, float y, float width, float height, Justification layout)
378{
380 ga.addJustifiedText (f, text, x, y, width, layout);
381
382 auto bb = ga.getBoundingBox (0, -1, false);
383 auto dy = y - bb.getY();
384
385 if (layout.testFlags (Justification::verticallyCentred)) dy += (height - bb.getHeight()) * 0.5f;
386 else if (layout.testFlags (Justification::bottom)) dy += (height - bb.getHeight());
387
388 ga.moveRangeOfGlyphs (0, -1, 0.0f, dy);
389
390 glyphs.addArray (ga.glyphs);
391}
392
393int GlyphArrangement::fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font& font,
394 Justification justification, float minimumHorizontalScale)
395{
396 int numDeleted = 0;
397 auto lineStartX = glyphs.getReference (start).getLeft();
398 auto lineWidth = glyphs.getReference (start + numGlyphs - 1).getRight() - lineStartX;
399
400 if (lineWidth > w)
401 {
402 if (minimumHorizontalScale < 1.0f)
403 {
404 stretchRangeOfGlyphs (start, numGlyphs, jmax (minimumHorizontalScale, w / lineWidth));
405 lineWidth = glyphs.getReference (start + numGlyphs - 1).getRight() - lineStartX - 0.5f;
406 }
407
408 if (lineWidth > w)
409 {
410 numDeleted = insertEllipsis (font, lineStartX + w, start, start + numGlyphs);
411 numGlyphs -= numDeleted;
412 }
413 }
414
415 justifyGlyphs (start, numGlyphs, x, y, w, h, justification);
416 return numDeleted;
417}
418
419void GlyphArrangement::stretchRangeOfGlyphs (int startIndex, int num, float horizontalScaleFactor)
420{
421 jassert (startIndex >= 0);
422
423 if (num < 0 || startIndex + num > glyphs.size())
424 num = glyphs.size() - startIndex;
425
426 if (num > 0)
427 {
428 auto xAnchor = glyphs.getReference (startIndex).getLeft();
429
430 while (--num >= 0)
431 {
432 auto& pg = glyphs.getReference (startIndex++);
433
434 pg.x = xAnchor + (pg.x - xAnchor) * horizontalScaleFactor;
435 pg.font.setHorizontalScale (pg.font.getHorizontalScale() * horizontalScaleFactor);
436 pg.w *= horizontalScaleFactor;
437 }
438 }
439}
440
441Rectangle<float> GlyphArrangement::getBoundingBox (int startIndex, int num, bool includeWhitespace) const
442{
443 jassert (startIndex >= 0);
444
445 if (num < 0 || startIndex + num > glyphs.size())
446 num = glyphs.size() - startIndex;
447
449
450 while (--num >= 0)
451 {
452 auto& pg = glyphs.getReference (startIndex++);
453
454 if (includeWhitespace || ! pg.isWhitespace())
455 result = result.getUnion (pg.getBounds());
456 }
457
458 return result;
459}
460
461void GlyphArrangement::justifyGlyphs (int startIndex, int num,
462 float x, float y, float width, float height,
463 Justification justification)
464{
465 jassert (num >= 0 && startIndex >= 0);
466
467 if (glyphs.size() > 0 && num > 0)
468 {
469 auto bb = getBoundingBox (startIndex, num, ! justification.testFlags (Justification::horizontallyJustified
471 float deltaX = x, deltaY = y;
472
473 if (justification.testFlags (Justification::horizontallyJustified)) deltaX -= bb.getX();
474 else if (justification.testFlags (Justification::horizontallyCentred)) deltaX += (width - bb.getWidth()) * 0.5f - bb.getX();
475 else if (justification.testFlags (Justification::right)) deltaX += width - bb.getRight();
476 else deltaX -= bb.getX();
477
478 if (justification.testFlags (Justification::top)) deltaY -= bb.getY();
479 else if (justification.testFlags (Justification::bottom)) deltaY += height - bb.getBottom();
480 else deltaY += (height - bb.getHeight()) * 0.5f - bb.getY();
481
482 moveRangeOfGlyphs (startIndex, num, deltaX, deltaY);
483
485 {
486 int lineStart = 0;
487 auto baseY = glyphs.getReference (startIndex).getBaselineY();
488
489 int i;
490 for (i = 0; i < num; ++i)
491 {
492 auto glyphY = glyphs.getReference (startIndex + i).getBaselineY();
493
494 if (glyphY != baseY)
495 {
496 spreadOutLine (startIndex + lineStart, i - lineStart, width);
497
498 lineStart = i;
499 baseY = glyphY;
500 }
501 }
502
503 if (i > lineStart)
504 spreadOutLine (startIndex + lineStart, i - lineStart, width);
505 }
506 }
507}
508
509void GlyphArrangement::spreadOutLine (int start, int num, float targetWidth)
510{
511 if (start + num < glyphs.size()
512 && glyphs.getReference (start + num - 1).getCharacter() != '\r'
513 && glyphs.getReference (start + num - 1).getCharacter() != '\n')
514 {
515 int numSpaces = 0;
516 int spacesAtEnd = 0;
517
518 for (int i = 0; i < num; ++i)
519 {
520 if (glyphs.getReference (start + i).isWhitespace())
521 {
522 ++spacesAtEnd;
523 ++numSpaces;
524 }
525 else
526 {
527 spacesAtEnd = 0;
528 }
529 }
530
531 numSpaces -= spacesAtEnd;
532
533 if (numSpaces > 0)
534 {
535 auto startX = glyphs.getReference (start).getLeft();
536 auto endX = glyphs.getReference (start + num - 1 - spacesAtEnd).getRight();
537
538 auto extraPaddingBetweenWords = (targetWidth - (endX - startX)) / (float) numSpaces;
539 float deltaX = 0.0f;
540
541 for (int i = 0; i < num; ++i)
542 {
543 glyphs.getReference (start + i).moveBy (deltaX, 0.0f);
544
545 if (glyphs.getReference (start + i).isWhitespace())
546 deltaX += extraPaddingBetweenWords;
547 }
548 }
549 }
550}
551
552static bool isBreakableGlyph (const PositionedGlyph& g) noexcept
553{
554 return ! isNonBreakingSpace (g.getCharacter()) && (g.isWhitespace() || g.getCharacter() == '-');
555}
556
557void GlyphArrangement::splitLines (const String& text, Font font, int startIndex,
558 float x, float y, float width, float height, int maximumLines,
559 float lineWidth, Justification layout, float minimumHorizontalScale)
560{
561 auto length = text.length();
562 auto originalStartIndex = startIndex;
563 int numLines = 1;
564
565 if (length <= 12 && ! text.containsAnyOf (" -\t\r\n"))
566 maximumLines = 1;
567
568 maximumLines = jmin (maximumLines, length);
569
570 while (numLines < maximumLines)
571 {
572 ++numLines;
573 auto newFontHeight = height / (float) numLines;
574
575 if (newFontHeight < font.getHeight())
576 {
577 font.setHeight (jmax (8.0f, newFontHeight));
578
579 removeRangeOfGlyphs (startIndex, -1);
580 addLineOfText (font, text, x, y);
581
582 lineWidth = glyphs.getReference (glyphs.size() - 1).getRight()
583 - glyphs.getReference (startIndex).getLeft();
584 }
585
586 // Try to estimate the point at which there are enough lines to fit the text,
587 // allowing for unevenness in the lengths due to differently sized words.
588 const float lineLengthUnevennessAllowance = 80.0f;
589
590 if ((float) numLines > (lineWidth + lineLengthUnevennessAllowance) / width || newFontHeight < 8.0f)
591 break;
592 }
593
594 if (numLines < 1)
595 numLines = 1;
596
597 int lineIndex = 0;
598 auto lineY = y;
599 auto widthPerLine = jmin (width / minimumHorizontalScale,
600 lineWidth / (float) numLines);
601
602 while (lineY < y + height)
603 {
604 auto endIndex = startIndex;
605 auto lineStartX = glyphs.getReference (startIndex).getLeft();
606 auto lineBottomY = lineY + font.getHeight();
607
608 if (lineIndex++ >= numLines - 1
609 || lineBottomY >= y + height)
610 {
611 widthPerLine = width;
612 endIndex = glyphs.size();
613 }
614 else
615 {
616 while (endIndex < glyphs.size())
617 {
618 if (glyphs.getReference (endIndex).getRight() - lineStartX > widthPerLine)
619 {
620 // got to a point where the line's too long, so skip forward to find a
621 // good place to break it..
622 auto searchStartIndex = endIndex;
623
624 while (endIndex < glyphs.size())
625 {
626 auto& g = glyphs.getReference (endIndex);
627
628 if ((g.getRight() - lineStartX) * minimumHorizontalScale < width)
629 {
630 if (isBreakableGlyph (g))
631 {
632 ++endIndex;
633 break;
634 }
635 }
636 else
637 {
638 // can't find a suitable break, so try looking backwards..
639 endIndex = searchStartIndex;
640
641 for (int back = 1; back < jmin (7, endIndex - startIndex - 1); ++back)
642 {
643 if (isBreakableGlyph (glyphs.getReference (endIndex - back)))
644 {
645 endIndex -= back - 1;
646 break;
647 }
648 }
649
650 break;
651 }
652
653 ++endIndex;
654 }
655
656 break;
657 }
658
659 ++endIndex;
660 }
661
662 auto wsStart = endIndex;
663 auto wsEnd = endIndex;
664
665 while (wsStart > 0 && glyphs.getReference (wsStart - 1).isWhitespace())
666 --wsStart;
667
668 while (wsEnd < glyphs.size() && glyphs.getReference (wsEnd).isWhitespace())
669 ++wsEnd;
670
671 removeRangeOfGlyphs (wsStart, wsEnd - wsStart);
672 endIndex = jmax (wsStart, startIndex + 1);
673 }
674
675 endIndex -= fitLineIntoSpace (startIndex, endIndex - startIndex,
676 x, lineY, width, font.getHeight(), font,
678 minimumHorizontalScale);
679
680 startIndex = endIndex;
681 lineY = lineBottomY;
682
683 if (startIndex >= glyphs.size())
684 break;
685 }
686
687 justifyGlyphs (originalStartIndex, glyphs.size() - originalStartIndex,
689}
690
691//==============================================================================
693 int i, AffineTransform transform) const
694{
695 auto lineThickness = (pg.font.getDescent()) * 0.3f;
696 auto nextX = pg.x + pg.w;
697
698 if (i < glyphs.size() - 1 && glyphs.getReference (i + 1).y == pg.y)
699 nextX = glyphs.getReference (i + 1).x;
700
701 Path p;
702 p.addRectangle (pg.x, pg.y + lineThickness * 2.0f, nextX - pg.x, lineThickness);
703 g.fillPath (p, transform);
704}
705
707{
708 draw (g, {});
709}
710
711void GlyphArrangement::draw (const Graphics& g, AffineTransform transform) const
712{
713 auto& context = g.getInternalContext();
714 auto lastFont = context.getFont();
715 bool needToRestore = false;
716
717 for (int i = 0; i < glyphs.size(); ++i)
718 {
719 auto& pg = glyphs.getReference (i);
720
721 if (pg.font.isUnderlined())
722 drawGlyphUnderline (g, pg, i, transform);
723
724 if (! pg.isWhitespace())
725 {
726 if (lastFont != pg.font)
727 {
728 lastFont = pg.font;
729
730 if (! needToRestore)
731 {
732 needToRestore = true;
733 context.saveState();
734 }
735
736 context.setFont (lastFont);
737 }
738
739 context.drawGlyph (pg.glyph, AffineTransform::translation (pg.x, pg.y)
740 .followedBy (transform));
741 }
742 }
743
744 if (needToRestore)
745 context.restoreState();
746}
747
749{
750 for (auto& g : glyphs)
751 g.createPath (path);
752}
753
754int GlyphArrangement::findGlyphIndexAt (float x, float y) const
755{
756 for (int i = 0; i < glyphs.size(); ++i)
757 if (glyphs.getReference (i).hitTest (x, y))
758 return i;
759
760 return -1;
761}
762
763} // namespace juce
Type jmin(const Type a, const Type b)
Definition MathsFunctions.h:60
Type jmax(const Type a, const Type b)
Definition MathsFunctions.h:48
#define noexcept
Definition DistrhoDefines.h:72
Definition juce_AffineTransform.h:43
static AffineTransform scale(float factorX, float factorY) noexcept
Definition juce_AffineTransform.cpp:141
static AffineTransform translation(float deltaX, float deltaY) noexcept
Definition juce_AffineTransform.cpp:81
Definition juce_Array.h:56
ElementType getUnchecked(int index) const
Definition juce_Array.h:252
int size() const noexcept
Definition juce_Array.h:215
ElementType getFirst() const noexcept
Definition juce_Array.h:290
Definition juce_Font.h:42
void getGlyphPositions(const String &text, Array< int > &glyphs, Array< float > &xOffsets) const
Definition juce_Font.cpp:757
static float getDefaultMinimumHorizontalScaleFactor() noexcept
Definition juce_Font.cpp:45
float getDescent() const
Definition juce_Font.cpp:736
float getHeight() const noexcept
Definition juce_Font.cpp:735
void setHeight(float newHeight)
Definition juce_Font.cpp:568
void clear()
Definition juce_GlyphArrangement.cpp:117
void addGlyph(const PositionedGlyph &)
Definition juce_GlyphArrangement.cpp:133
void addLineOfText(const Font &font, const String &text, float x, float y)
Definition juce_GlyphArrangement.cpp:144
void createPath(Path &path) const
Definition juce_GlyphArrangement.cpp:748
void stretchRangeOfGlyphs(int startIndex, int numGlyphs, float horizontalScaleFactor)
Definition juce_GlyphArrangement.cpp:419
Rectangle< float > getBoundingBox(int startIndex, int numGlyphs, bool includeWhitespace) const
Definition juce_GlyphArrangement.cpp:441
void splitLines(const String &, Font, int start, float x, float y, float w, float h, int maxLines, float lineWidth, Justification, float minimumHorizontalScale)
Definition juce_GlyphArrangement.cpp:557
void addLinesWithLineBreaks(const String &, const Font &, float x, float y, float width, float height, Justification)
Definition juce_GlyphArrangement.cpp:376
int insertEllipsis(const Font &, float maxXPos, int startIndex, int endIndex)
Definition juce_GlyphArrangement.cpp:187
void addFittedText(const Font &font, const String &text, float x, float y, float width, float height, Justification layout, int maximumLinesToUse, float minimumHorizontalScale=0.0f)
Definition juce_GlyphArrangement.cpp:310
void addCurtailedLineOfText(const Font &font, const String &text, float x, float y, float maxWidthPixels, bool useEllipsis)
Definition juce_GlyphArrangement.cpp:149
Array< PositionedGlyph > glyphs
Definition juce_GlyphArrangement.h:307
void addJustifiedText(const Font &font, const String &text, float x, float y, float maxLineWidth, Justification horizontalLayout, float leading=0.0f)
Definition juce_GlyphArrangement.cpp:228
int findGlyphIndexAt(float x, float y) const
Definition juce_GlyphArrangement.cpp:754
void draw(const Graphics &) const
Definition juce_GlyphArrangement.cpp:706
GlyphArrangement()
Definition juce_GlyphArrangement.cpp:111
PositionedGlyph & getGlyph(int index) noexcept
Definition juce_GlyphArrangement.cpp:122
void addGlyphArrangement(const GlyphArrangement &)
Definition juce_GlyphArrangement.cpp:128
void drawGlyphUnderline(const Graphics &, const PositionedGlyph &, int, AffineTransform) const
Definition juce_GlyphArrangement.cpp:692
void justifyGlyphs(int startIndex, int numGlyphs, float x, float y, float width, float height, Justification justification)
Definition juce_GlyphArrangement.cpp:461
void moveRangeOfGlyphs(int startIndex, int numGlyphs, float deltaX, float deltaY)
Definition juce_GlyphArrangement.cpp:362
int fitLineIntoSpace(int start, int numGlyphs, float x, float y, float w, float h, const Font &, Justification, float minimumHorizontalScale)
Definition juce_GlyphArrangement.cpp:393
void removeRangeOfGlyphs(int startIndex, int numGlyphs)
Definition juce_GlyphArrangement.cpp:138
void spreadOutLine(int start, int numGlyphs, float targetWidth)
Definition juce_GlyphArrangement.cpp:509
Definition juce_GraphicsContext.h:45
Definition juce_Justification.h:41
@ horizontallyJustified
Definition juce_Justification.h:132
@ horizontallyCentred
Definition juce_Justification.h:115
@ bottom
Definition juce_Justification.h:122
@ verticallyCentred
Definition juce_Justification.h:126
@ top
Definition juce_Justification.h:119
@ right
Definition juce_Justification.h:111
int getOnlyHorizontalFlags() const noexcept
Definition juce_Justification.h:69
int getFlags() const noexcept
Definition juce_Justification.h:58
bool testFlags(int flagsToTest) const noexcept
Definition juce_Justification.h:63
Definition juce_Path.h:65
void addPath(const Path &pathToAppend)
Definition juce_Path.cpp:726
Definition juce_GlyphArrangement.h:42
PositionedGlyph() noexcept
Definition juce_GlyphArrangement.cpp:37
float w
Definition juce_GlyphArrangement.h:97
void draw(Graphics &g) const
Definition juce_GlyphArrangement.cpp:56
float y
Definition juce_GlyphArrangement.h:97
bool isWhitespace() const noexcept
Definition juce_GlyphArrangement.h:53
float x
Definition juce_GlyphArrangement.h:97
bool hitTest(float x, float y) const
Definition juce_GlyphArrangement.cpp:83
int glyph
Definition juce_GlyphArrangement.h:96
bool whitespace
Definition juce_GlyphArrangement.h:98
Font font
Definition juce_GlyphArrangement.h:94
void moveBy(float deltaX, float deltaY)
Definition juce_GlyphArrangement.cpp:103
Rectangle< float > getBounds() const
Definition juce_GlyphArrangement.h:66
void createPath(Path &path) const
Definition juce_GlyphArrangement.cpp:68
juce_wchar character
Definition juce_GlyphArrangement.h:95
Definition juce_Rectangle.h:67
Definition juce_String.h:53
UINT_D64 w
Definition inflate.c:942
G bb
Definition inflate.c:1057
struct huft * t
Definition inflate.c:943
register unsigned j
Definition inflate.c:1576
int y
Definition inflate.c:1588
int g
Definition inflate.c:1573
register unsigned i
Definition inflate.c:1575
unsigned x[BMAX+1]
Definition inflate.c:1586
unsigned f
Definition inflate.c:1572
static int int height
Definition pugl.h:1594
static int width
Definition pugl.h:1593
virtual ASIOError start()=0
#define jassert(expression)
Definition carla_juce.cpp:31
static constexpr bool isNonBreakingSpace(const juce_wchar c)
Definition juce_GlyphArrangement.cpp:29
constexpr Type jmax(Type a, Type b)
Definition juce_MathsFunctions.h:94
static void drawGlyphWithFont(Graphics &g, int glyph, const Font &font, AffineTransform t)
Definition juce_GlyphArrangement.cpp:49
static bool isBreakableGlyph(const PositionedGlyph &g) noexcept
Definition juce_GlyphArrangement.cpp:552
wchar_t juce_wchar
Definition juce_CharacterFunctions.h:42
#define false
Definition ordinals.h:83
png_uint_32 length
Definition png.c:2247
const char * text
Definition swell-functions.h:167
uch * p
Definition crypt.c:594
return c
Definition crypt.c:175
uch h[RAND_HEAD_LEN]
Definition crypt.c:459
int result
Definition process.c:1455
dy
Definition zipinfo.c:2288