| @@ -42,7 +42,8 @@ public: | |||
| // Create the editor.. | |||
| addAndMakeVisible (editor = new CodeEditorComponent (codeDocument, &cppTokeniser)); | |||
| editor->loadContent ("\n\n/* Code editor demo! Please be gentle, this component is still an alpha version! */\n\n"); | |||
| editor->loadContent ("\n\n/* Code editor demo! To see a real-world example of the " | |||
| "code editor in action, try the Introjucer! */\n\n"); | |||
| // Create a file chooser control to load files into it.. | |||
| addAndMakeVisible (&fileChooser); | |||
| @@ -48,16 +48,17 @@ LowLevelGraphicsContext::~LowLevelGraphicsContext() | |||
| //============================================================================== | |||
| Graphics::Graphics (const Image& imageToDrawOnto) | |||
| : context (imageToDrawOnto.createLowLevelContext()), | |||
| contextToDelete (context), | |||
| : context (*imageToDrawOnto.createLowLevelContext()), | |||
| contextToDelete (&context), | |||
| saveStatePending (false) | |||
| { | |||
| } | |||
| Graphics::Graphics (LowLevelGraphicsContext* const internalContext) noexcept | |||
| : context (internalContext), | |||
| : context (*internalContext), | |||
| saveStatePending (false) | |||
| { | |||
| jassert (internalContext != nullptr); | |||
| } | |||
| Graphics::~Graphics() | |||
| @@ -68,20 +69,20 @@ Graphics::~Graphics() | |||
| void Graphics::resetToDefaultState() | |||
| { | |||
| saveStateIfPending(); | |||
| context->setFill (FillType()); | |||
| context->setFont (Font()); | |||
| context->setInterpolationQuality (Graphics::mediumResamplingQuality); | |||
| context.setFill (FillType()); | |||
| context.setFont (Font()); | |||
| context.setInterpolationQuality (Graphics::mediumResamplingQuality); | |||
| } | |||
| bool Graphics::isVectorDevice() const | |||
| { | |||
| return context->isVectorDevice(); | |||
| return context.isVectorDevice(); | |||
| } | |||
| bool Graphics::reduceClipRegion (const Rectangle<int>& area) | |||
| { | |||
| saveStateIfPending(); | |||
| return context->clipToRectangle (area); | |||
| return context.clipToRectangle (area); | |||
| } | |||
| bool Graphics::reduceClipRegion (const int x, const int y, const int w, const int h) | |||
| @@ -92,37 +93,37 @@ bool Graphics::reduceClipRegion (const int x, const int y, const int w, const in | |||
| bool Graphics::reduceClipRegion (const RectangleList& clipRegion) | |||
| { | |||
| saveStateIfPending(); | |||
| return context->clipToRectangleList (clipRegion); | |||
| return context.clipToRectangleList (clipRegion); | |||
| } | |||
| bool Graphics::reduceClipRegion (const Path& path, const AffineTransform& transform) | |||
| { | |||
| saveStateIfPending(); | |||
| context->clipToPath (path, transform); | |||
| return ! context->isClipEmpty(); | |||
| context.clipToPath (path, transform); | |||
| return ! context.isClipEmpty(); | |||
| } | |||
| bool Graphics::reduceClipRegion (const Image& image, const AffineTransform& transform) | |||
| { | |||
| saveStateIfPending(); | |||
| context->clipToImageAlpha (image, transform); | |||
| return ! context->isClipEmpty(); | |||
| context.clipToImageAlpha (image, transform); | |||
| return ! context.isClipEmpty(); | |||
| } | |||
| void Graphics::excludeClipRegion (const Rectangle<int>& rectangleToExclude) | |||
| { | |||
| saveStateIfPending(); | |||
| context->excludeClipRectangle (rectangleToExclude); | |||
| context.excludeClipRectangle (rectangleToExclude); | |||
| } | |||
| bool Graphics::isClipEmpty() const | |||
| { | |||
| return context->isClipEmpty(); | |||
| return context.isClipEmpty(); | |||
| } | |||
| Rectangle<int> Graphics::getClipBounds() const | |||
| { | |||
| return context->getClipBounds(); | |||
| return context.getClipBounds(); | |||
| } | |||
| void Graphics::saveState() | |||
| @@ -136,7 +137,7 @@ void Graphics::restoreState() | |||
| if (saveStatePending) | |||
| saveStatePending = false; | |||
| else | |||
| context->restoreState(); | |||
| context.restoreState(); | |||
| } | |||
| void Graphics::saveStateIfPending() | |||
| @@ -144,49 +145,49 @@ void Graphics::saveStateIfPending() | |||
| if (saveStatePending) | |||
| { | |||
| saveStatePending = false; | |||
| context->saveState(); | |||
| context.saveState(); | |||
| } | |||
| } | |||
| void Graphics::setOrigin (const int newOriginX, const int newOriginY) | |||
| { | |||
| saveStateIfPending(); | |||
| context->setOrigin (newOriginX, newOriginY); | |||
| context.setOrigin (newOriginX, newOriginY); | |||
| } | |||
| void Graphics::addTransform (const AffineTransform& transform) | |||
| { | |||
| saveStateIfPending(); | |||
| context->addTransform (transform); | |||
| context.addTransform (transform); | |||
| } | |||
| bool Graphics::clipRegionIntersects (const Rectangle<int>& area) const | |||
| { | |||
| return context->clipRegionIntersects (area); | |||
| return context.clipRegionIntersects (area); | |||
| } | |||
| void Graphics::beginTransparencyLayer (float layerOpacity) | |||
| { | |||
| saveStateIfPending(); | |||
| context->beginTransparencyLayer (layerOpacity); | |||
| context.beginTransparencyLayer (layerOpacity); | |||
| } | |||
| void Graphics::endTransparencyLayer() | |||
| { | |||
| context->endTransparencyLayer(); | |||
| context.endTransparencyLayer(); | |||
| } | |||
| //============================================================================== | |||
| void Graphics::setColour (const Colour& newColour) | |||
| { | |||
| saveStateIfPending(); | |||
| context->setFill (newColour); | |||
| context.setFill (newColour); | |||
| } | |||
| void Graphics::setOpacity (const float newOpacity) | |||
| { | |||
| saveStateIfPending(); | |||
| context->setOpacity (newOpacity); | |||
| context.setOpacity (newOpacity); | |||
| } | |||
| void Graphics::setGradientFill (const ColourGradient& gradient) | |||
| @@ -197,31 +198,31 @@ void Graphics::setGradientFill (const ColourGradient& gradient) | |||
| void Graphics::setTiledImageFill (const Image& imageToUse, const int anchorX, const int anchorY, const float opacity) | |||
| { | |||
| saveStateIfPending(); | |||
| context->setFill (FillType (imageToUse, AffineTransform::translation ((float) anchorX, (float) anchorY))); | |||
| context->setOpacity (opacity); | |||
| context.setFill (FillType (imageToUse, AffineTransform::translation ((float) anchorX, (float) anchorY))); | |||
| context.setOpacity (opacity); | |||
| } | |||
| void Graphics::setFillType (const FillType& newFill) | |||
| { | |||
| saveStateIfPending(); | |||
| context->setFill (newFill); | |||
| context.setFill (newFill); | |||
| } | |||
| //============================================================================== | |||
| void Graphics::setFont (const Font& newFont) | |||
| { | |||
| saveStateIfPending(); | |||
| context->setFont (newFont); | |||
| context.setFont (newFont); | |||
| } | |||
| void Graphics::setFont (const float newFontHeight) | |||
| { | |||
| setFont (context->getFont().withHeight (newFontHeight)); | |||
| setFont (context.getFont().withHeight (newFontHeight)); | |||
| } | |||
| Font Graphics::getCurrentFont() const | |||
| { | |||
| return context->getFont(); | |||
| return context.getFont(); | |||
| } | |||
| //============================================================================== | |||
| @@ -229,10 +230,10 @@ void Graphics::drawSingleLineText (const String& text, const int startX, const i | |||
| const Justification& justification) const | |||
| { | |||
| if (text.isNotEmpty() | |||
| && startX < context->getClipBounds().getRight()) | |||
| && startX < context.getClipBounds().getRight()) | |||
| { | |||
| GlyphArrangement arr; | |||
| arr.addLineOfText (context->getFont(), text, (float) startX, (float) baselineY); | |||
| arr.addLineOfText (context.getFont(), text, (float) startX, (float) baselineY); | |||
| // Don't pass any vertical placement flags to this method - they'll be ignored. | |||
| jassert (justification.getOnlyVerticalFlags() == 0); | |||
| @@ -260,7 +261,7 @@ void Graphics::drawTextAsPath (const String& text, const AffineTransform& transf | |||
| if (text.isNotEmpty()) | |||
| { | |||
| GlyphArrangement arr; | |||
| arr.addLineOfText (context->getFont(), text, 0.0f, 0.0f); | |||
| arr.addLineOfText (context.getFont(), text, 0.0f, 0.0f); | |||
| arr.draw (*this, transform); | |||
| } | |||
| } | |||
| @@ -268,10 +269,10 @@ void Graphics::drawTextAsPath (const String& text, const AffineTransform& transf | |||
| void Graphics::drawMultiLineText (const String& text, const int startX, const int baselineY, const int maximumLineWidth) const | |||
| { | |||
| if (text.isNotEmpty() | |||
| && startX < context->getClipBounds().getRight()) | |||
| && startX < context.getClipBounds().getRight()) | |||
| { | |||
| GlyphArrangement arr; | |||
| arr.addJustifiedText (context->getFont(), text, | |||
| arr.addJustifiedText (context.getFont(), text, | |||
| (float) startX, (float) baselineY, (float) maximumLineWidth, | |||
| Justification::left); | |||
| arr.draw (*this); | |||
| @@ -283,11 +284,11 @@ void Graphics::drawText (const String& text, | |||
| const Justification& justificationType, | |||
| const bool useEllipsesIfTooBig) const | |||
| { | |||
| if (text.isNotEmpty() && context->clipRegionIntersects (Rectangle<int> (x, y, width, height))) | |||
| if (text.isNotEmpty() && context.clipRegionIntersects (Rectangle<int> (x, y, width, height))) | |||
| { | |||
| GlyphArrangement arr; | |||
| arr.addCurtailedLineOfText (context->getFont(), text, | |||
| arr.addCurtailedLineOfText (context.getFont(), text, | |||
| 0.0f, 0.0f, (float) width, | |||
| useEllipsesIfTooBig); | |||
| @@ -306,11 +307,11 @@ void Graphics::drawFittedText (const String& text, | |||
| { | |||
| if (text.isNotEmpty() | |||
| && width > 0 && height > 0 | |||
| && context->clipRegionIntersects (Rectangle<int> (x, y, width, height))) | |||
| && context.clipRegionIntersects (Rectangle<int> (x, y, width, height))) | |||
| { | |||
| GlyphArrangement arr; | |||
| arr.addFittedText (context->getFont(), text, | |||
| arr.addFittedText (context.getFont(), text, | |||
| (float) x, (float) y, (float) width, (float) height, | |||
| justification, | |||
| maximumNumberOfLines, | |||
| @@ -326,12 +327,12 @@ void Graphics::fillRect (int x, int y, int width, int height) const | |||
| // passing in a silly number can cause maths problems in rendering! | |||
| jassert (areCoordsSensibleNumbers (x, y, width, height)); | |||
| context->fillRect (Rectangle<int> (x, y, width, height), false); | |||
| context.fillRect (Rectangle<int> (x, y, width, height), false); | |||
| } | |||
| void Graphics::fillRect (const Rectangle<int>& r) const | |||
| { | |||
| context->fillRect (r, false); | |||
| context.fillRect (r, false); | |||
| } | |||
| void Graphics::fillRect (const float x, const float y, const float width, const float height) const | |||
| @@ -346,24 +347,24 @@ void Graphics::fillRect (const float x, const float y, const float width, const | |||
| void Graphics::setPixel (int x, int y) const | |||
| { | |||
| context->fillRect (Rectangle<int> (x, y, 1, 1), false); | |||
| context.fillRect (Rectangle<int> (x, y, 1, 1), false); | |||
| } | |||
| void Graphics::fillAll() const | |||
| { | |||
| fillRect (context->getClipBounds()); | |||
| fillRect (context.getClipBounds()); | |||
| } | |||
| void Graphics::fillAll (const Colour& colourToUse) const | |||
| { | |||
| if (! colourToUse.isTransparent()) | |||
| { | |||
| const Rectangle<int> clip (context->getClipBounds()); | |||
| const Rectangle<int> clip (context.getClipBounds()); | |||
| context->saveState(); | |||
| context->setFill (colourToUse); | |||
| context->fillRect (clip, false); | |||
| context->restoreState(); | |||
| context.saveState(); | |||
| context.setFill (colourToUse); | |||
| context.fillRect (clip, false); | |||
| context.restoreState(); | |||
| } | |||
| } | |||
| @@ -371,8 +372,8 @@ void Graphics::fillAll (const Colour& colourToUse) const | |||
| //============================================================================== | |||
| void Graphics::fillPath (const Path& path, const AffineTransform& transform) const | |||
| { | |||
| if ((! context->isClipEmpty()) && ! path.isEmpty()) | |||
| context->fillPath (path, transform); | |||
| if ((! context.isClipEmpty()) && ! path.isEmpty()) | |||
| context.fillPath (path, transform); | |||
| } | |||
| void Graphics::strokePath (const Path& path, | |||
| @@ -380,7 +381,7 @@ void Graphics::strokePath (const Path& path, | |||
| const AffineTransform& transform) const | |||
| { | |||
| Path stroke; | |||
| strokeType.createStrokedPath (stroke, path, transform, context->getScaleFactor()); | |||
| strokeType.createStrokedPath (stroke, path, transform, context.getScaleFactor()); | |||
| fillPath (stroke); | |||
| } | |||
| @@ -391,10 +392,10 @@ void Graphics::drawRect (const int x, const int y, const int width, const int he | |||
| // passing in a silly number can cause maths problems in rendering! | |||
| jassert (areCoordsSensibleNumbers (x, y, width, height)); | |||
| context->fillRect (Rectangle<int> (x, y, width, lineThickness), false); | |||
| context->fillRect (Rectangle<int> (x, y + lineThickness, lineThickness, height - lineThickness * 2), false); | |||
| context->fillRect (Rectangle<int> (x + width - lineThickness, y + lineThickness, lineThickness, height - lineThickness * 2), false); | |||
| context->fillRect (Rectangle<int> (x, y + height - lineThickness, width, lineThickness), false); | |||
| context.fillRect (Rectangle<int> (x, y, width, lineThickness), false); | |||
| context.fillRect (Rectangle<int> (x, y + lineThickness, lineThickness, height - lineThickness * 2), false); | |||
| context.fillRect (Rectangle<int> (x + width - lineThickness, y + lineThickness, lineThickness, height - lineThickness * 2), false); | |||
| context.fillRect (Rectangle<int> (x, y + height - lineThickness, width, lineThickness), false); | |||
| } | |||
| void Graphics::drawRect (const float x, const float y, const float width, const float height, const float lineThickness) const | |||
| @@ -424,24 +425,24 @@ void Graphics::drawBevel (const int x, const int y, const int width, const int h | |||
| if (clipRegionIntersects (Rectangle<int> (x, y, width, height))) | |||
| { | |||
| context->saveState(); | |||
| context.saveState(); | |||
| for (int i = bevelThickness; --i >= 0;) | |||
| { | |||
| const float op = useGradient ? (sharpEdgeOnOutside ? bevelThickness - i : i) / (float) bevelThickness | |||
| : 1.0f; | |||
| context->setFill (topLeftColour.withMultipliedAlpha (op)); | |||
| context->fillRect (Rectangle<int> (x + i, y + i, width - i * 2, 1), false); | |||
| context->setFill (topLeftColour.withMultipliedAlpha (op * 0.75f)); | |||
| context->fillRect (Rectangle<int> (x + i, y + i + 1, 1, height - i * 2 - 2), false); | |||
| context->setFill (bottomRightColour.withMultipliedAlpha (op)); | |||
| context->fillRect (Rectangle<int> (x + i, y + height - i - 1, width - i * 2, 1), false); | |||
| context->setFill (bottomRightColour.withMultipliedAlpha (op * 0.75f)); | |||
| context->fillRect (Rectangle<int> (x + width - i - 1, y + i + 1, 1, height - i * 2 - 2), false); | |||
| context.setFill (topLeftColour.withMultipliedAlpha (op)); | |||
| context.fillRect (Rectangle<int> (x + i, y + i, width - i * 2, 1), false); | |||
| context.setFill (topLeftColour.withMultipliedAlpha (op * 0.75f)); | |||
| context.fillRect (Rectangle<int> (x + i, y + i + 1, 1, height - i * 2 - 2), false); | |||
| context.setFill (bottomRightColour.withMultipliedAlpha (op)); | |||
| context.fillRect (Rectangle<int> (x + i, y + height - i - 1, width - i * 2, 1), false); | |||
| context.setFill (bottomRightColour.withMultipliedAlpha (op * 0.75f)); | |||
| context.fillRect (Rectangle<int> (x + width - i - 1, y + i + 1, 1, height - i * 2 - 2), false); | |||
| } | |||
| context->restoreState(); | |||
| context.restoreState(); | |||
| } | |||
| } | |||
| @@ -518,20 +519,20 @@ void Graphics::fillCheckerBoard (const Rectangle<int>& area, | |||
| if (checkWidth > 0 && checkHeight > 0) | |||
| { | |||
| context->saveState(); | |||
| context.saveState(); | |||
| if (colour1 == colour2) | |||
| { | |||
| context->setFill (colour1); | |||
| context->fillRect (area, false); | |||
| context.setFill (colour1); | |||
| context.fillRect (area, false); | |||
| } | |||
| else | |||
| { | |||
| const Rectangle<int> clipped (context->getClipBounds().getIntersection (area)); | |||
| const Rectangle<int> clipped (context.getClipBounds().getIntersection (area)); | |||
| if (! clipped.isEmpty()) | |||
| { | |||
| context->clipToRectangle (clipped); | |||
| context.clipToRectangle (clipped); | |||
| const int checkNumX = (clipped.getX() - area.getX()) / checkWidth; | |||
| const int checkNumY = (clipped.getY() - area.getY()) / checkHeight; | |||
| @@ -542,39 +543,39 @@ void Graphics::fillCheckerBoard (const Rectangle<int>& area, | |||
| for (int i = 0; i < 2; ++i) | |||
| { | |||
| context->setFill (i == ((checkNumX ^ checkNumY) & 1) ? colour1 : colour2); | |||
| context.setFill (i == ((checkNumX ^ checkNumY) & 1) ? colour1 : colour2); | |||
| int cy = i; | |||
| for (int y = startY; y < bottom; y += checkHeight) | |||
| for (int x = startX + (cy++ & 1) * checkWidth; x < right; x += checkWidth * 2) | |||
| context->fillRect (Rectangle<int> (x, y, checkWidth, checkHeight), false); | |||
| context.fillRect (Rectangle<int> (x, y, checkWidth, checkHeight), false); | |||
| } | |||
| } | |||
| } | |||
| context->restoreState(); | |||
| context.restoreState(); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| void Graphics::drawVerticalLine (const int x, float top, float bottom) const | |||
| { | |||
| context->drawVerticalLine (x, top, bottom); | |||
| context.drawVerticalLine (x, top, bottom); | |||
| } | |||
| void Graphics::drawHorizontalLine (const int y, float left, float right) const | |||
| { | |||
| context->drawHorizontalLine (y, left, right); | |||
| context.drawHorizontalLine (y, left, right); | |||
| } | |||
| void Graphics::drawLine (const float x1, const float y1, const float x2, const float y2) const | |||
| { | |||
| context->drawLine (Line<float> (x1, y1, x2, y2)); | |||
| context.drawLine (Line<float> (x1, y1, x2, y2)); | |||
| } | |||
| void Graphics::drawLine (const Line<float>& line) const | |||
| { | |||
| context->drawLine (line); | |||
| context.drawLine (line); | |||
| } | |||
| void Graphics::drawLine (const float x1, const float y1, const float x2, const float y2, const float lineThickness) const | |||
| @@ -617,7 +618,7 @@ void Graphics::drawDashedLine (const Line<float>& line, const float* const dashL | |||
| if (lineThickness != 1.0f) | |||
| drawLine (segment, lineThickness); | |||
| else | |||
| context->drawLine (segment); | |||
| context.drawLine (segment); | |||
| } | |||
| } | |||
| } | |||
| @@ -627,7 +628,7 @@ void Graphics::drawDashedLine (const Line<float>& line, const float* const dashL | |||
| void Graphics::setImageResamplingQuality (const Graphics::ResamplingQuality newQuality) | |||
| { | |||
| saveStateIfPending(); | |||
| context->setInterpolationQuality (newQuality); | |||
| context.setInterpolationQuality (newQuality); | |||
| } | |||
| //============================================================================== | |||
| @@ -688,7 +689,7 @@ void Graphics::drawImage (const Image& imageToDraw, | |||
| jassert (areCoordsSensibleNumbers (dx, dy, dw, dh)); | |||
| jassert (areCoordsSensibleNumbers (sx, sy, sw, sh)); | |||
| if (imageToDraw.isValid() && context->clipRegionIntersects (Rectangle<int> (dx, dy, dw, dh))) | |||
| if (imageToDraw.isValid() && context.clipRegionIntersects (Rectangle<int> (dx, dy, dw, dh))) | |||
| { | |||
| drawImageTransformed (imageToDraw.getClippedImage (Rectangle<int> (sx, sy, sw, sh)), | |||
| AffineTransform::scale (dw / (float) sw, dh / (float) sh) | |||
| @@ -701,18 +702,18 @@ void Graphics::drawImageTransformed (const Image& imageToDraw, | |||
| const AffineTransform& transform, | |||
| const bool fillAlphaChannelWithCurrentBrush) const | |||
| { | |||
| if (imageToDraw.isValid() && ! context->isClipEmpty()) | |||
| if (imageToDraw.isValid() && ! context.isClipEmpty()) | |||
| { | |||
| if (fillAlphaChannelWithCurrentBrush) | |||
| { | |||
| context->saveState(); | |||
| context->clipToImageAlpha (imageToDraw, transform); | |||
| context.saveState(); | |||
| context.clipToImageAlpha (imageToDraw, transform); | |||
| fillAll(); | |||
| context->restoreState(); | |||
| context.restoreState(); | |||
| } | |||
| else | |||
| { | |||
| context->drawImage (imageToDraw, transform); | |||
| context.drawImage (imageToDraw, transform); | |||
| } | |||
| } | |||
| } | |||
| @@ -688,14 +688,14 @@ public: | |||
| For internal use only. | |||
| NB. The context will NOT be deleted by this object when it is deleted. | |||
| */ | |||
| Graphics (LowLevelGraphicsContext* internalContext) noexcept; | |||
| Graphics (LowLevelGraphicsContext*) noexcept; | |||
| /** @internal */ | |||
| LowLevelGraphicsContext* getInternalContext() const noexcept { return context; } | |||
| LowLevelGraphicsContext& getInternalContext() const noexcept { return context; } | |||
| private: | |||
| //============================================================================== | |||
| LowLevelGraphicsContext* const context; | |||
| LowLevelGraphicsContext& context; | |||
| ScopedPointer <LowLevelGraphicsContext> contextToDelete; | |||
| bool saveStatePending; | |||
| @@ -207,7 +207,7 @@ void AttributedString::draw (Graphics& g, const Rectangle<float>& area) const | |||
| { | |||
| if (text.isNotEmpty() && g.clipRegionIntersects (area.getSmallestIntegerContainer())) | |||
| { | |||
| if (! g.getInternalContext()->drawTextLayout (*this, area)) | |||
| if (! g.getInternalContext().drawTextLayout (*this, area)) | |||
| { | |||
| TextLayout layout; | |||
| layout.createLayout (*this, area.getWidth()); | |||
| @@ -212,7 +212,6 @@ public: | |||
| //============================================================================== | |||
| /** Returns the total height of this font. | |||
| This is the maximum height, from the top of the ascent to the bottom of the | |||
| descenders. | |||
| @@ -288,7 +287,6 @@ public: | |||
| //============================================================================== | |||
| /** Returns the font's horizontal scale. | |||
| A value of 1.0 is the normal scale, less than this will be narrower, greater | |||
| than 1.0 will be stretched out. | |||
| @@ -350,13 +348,11 @@ public: | |||
| //============================================================================== | |||
| /** Returns the total width of a string as it would be drawn using this font. | |||
| For a more accurate floating-point result, use getStringWidthFloat(). | |||
| */ | |||
| int getStringWidth (const String& text) const; | |||
| /** Returns the total width of a string as it would be drawn using this font. | |||
| @see getStringWidth | |||
| */ | |||
| float getStringWidthFloat (const String& text) const; | |||
| @@ -23,6 +23,11 @@ | |||
| ============================================================================== | |||
| */ | |||
| PositionedGlyph::PositionedGlyph() noexcept | |||
| : character (0), glyph (0), x (0), y (0), w (0), whitespace (false) | |||
| { | |||
| } | |||
| PositionedGlyph::PositionedGlyph (const Font& font_, const juce_wchar character_, const int glyph_, | |||
| const float x_, const float y_, const float w_, const bool whitespace_) | |||
| : font (font_), character (character_), glyph (glyph_), | |||
| @@ -54,21 +59,19 @@ void PositionedGlyph::draw (const Graphics& g) const | |||
| { | |||
| if (! isWhitespace()) | |||
| { | |||
| LowLevelGraphicsContext* const context = g.getInternalContext(); | |||
| context->setFont (font); | |||
| context->drawGlyph (glyph, AffineTransform::translation (x, y)); | |||
| LowLevelGraphicsContext& context = g.getInternalContext(); | |||
| context.setFont (font); | |||
| context.drawGlyph (glyph, AffineTransform::translation (x, y)); | |||
| } | |||
| } | |||
| void PositionedGlyph::draw (const Graphics& g, | |||
| const AffineTransform& transform) const | |||
| void PositionedGlyph::draw (const Graphics& g, const AffineTransform& transform) const | |||
| { | |||
| if (! isWhitespace()) | |||
| { | |||
| LowLevelGraphicsContext* const context = g.getInternalContext(); | |||
| context->setFont (font); | |||
| context->drawGlyph (glyph, AffineTransform::translation (x, y) | |||
| .followedBy (transform)); | |||
| LowLevelGraphicsContext& context = g.getInternalContext(); | |||
| context.setFont (font); | |||
| context.drawGlyph (glyph, AffineTransform::translation (x, y).followedBy (transform)); | |||
| } | |||
| } | |||
| @@ -126,18 +129,13 @@ GlyphArrangement::GlyphArrangement() | |||
| } | |||
| GlyphArrangement::GlyphArrangement (const GlyphArrangement& other) | |||
| : glyphs (other.glyphs) | |||
| { | |||
| addGlyphArrangement (other); | |||
| } | |||
| GlyphArrangement& GlyphArrangement::operator= (const GlyphArrangement& other) | |||
| { | |||
| if (this != &other) | |||
| { | |||
| clear(); | |||
| addGlyphArrangement (other); | |||
| } | |||
| glyphs = other.glyphs; | |||
| return *this; | |||
| } | |||
| @@ -151,23 +149,20 @@ void GlyphArrangement::clear() | |||
| glyphs.clear(); | |||
| } | |||
| PositionedGlyph& GlyphArrangement::getGlyph (const int index) const | |||
| PositionedGlyph& GlyphArrangement::getGlyph (const int index) const noexcept | |||
| { | |||
| jassert (isPositiveAndBelow (index, glyphs.size())); | |||
| return *glyphs [index]; | |||
| return glyphs.getReference (index); | |||
| } | |||
| //============================================================================== | |||
| void GlyphArrangement::addGlyphArrangement (const GlyphArrangement& other) | |||
| { | |||
| glyphs.ensureStorageAllocated (glyphs.size() + other.glyphs.size()); | |||
| glyphs.addCopiesOf (other.glyphs); | |||
| glyphs.addArray (other.glyphs); | |||
| } | |||
| void GlyphArrangement::addGlyph (const PositionedGlyph& glyph) | |||
| { | |||
| glyphs.add (new PositionedGlyph (glyph)); | |||
| glyphs.add (glyph); | |||
| } | |||
| void GlyphArrangement::removeRangeOfGlyphs (int startIndex, const int num) | |||
| @@ -181,9 +176,7 @@ void GlyphArrangement::addLineOfText (const Font& font, | |||
| const float xOffset, | |||
| const float yOffset) | |||
| { | |||
| addCurtailedLineOfText (font, text, | |||
| xOffset, yOffset, | |||
| 1.0e10f, false); | |||
| addCurtailedLineOfText (font, text, xOffset, yOffset, 1.0e10f, false); | |||
| } | |||
| void GlyphArrangement::addCurtailedLineOfText (const Font& font, | |||
| @@ -205,7 +198,6 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, | |||
| for (int i = 0; i < textLen; ++i) | |||
| { | |||
| const float thisX = xOffsets.getUnchecked (i); | |||
| const float nextX = xOffsets.getUnchecked (i + 1); | |||
| if (nextX > maxWidthPixels + 1.0f) | |||
| @@ -218,12 +210,13 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, | |||
| } | |||
| else | |||
| { | |||
| const float thisX = xOffsets.getUnchecked (i); | |||
| const bool isWhitespace = t.isWhitespace(); | |||
| glyphs.add (new PositionedGlyph (font, t.getAndAdvance(), | |||
| newGlyphs.getUnchecked(i), | |||
| xOffset + thisX, yOffset, | |||
| nextX - thisX, isWhitespace)); | |||
| glyphs.add (PositionedGlyph (font, t.getAndAdvance(), | |||
| newGlyphs.getUnchecked(i), | |||
| xOffset + thisX, yOffset, | |||
| nextX - thisX, isWhitespace)); | |||
| } | |||
| } | |||
| } | |||
| @@ -245,9 +238,9 @@ int GlyphArrangement::insertEllipsis (const Font& font, const float maxXPos, | |||
| while (endIndex > startIndex) | |||
| { | |||
| const PositionedGlyph* pg = glyphs.getUnchecked (--endIndex); | |||
| xOffset = pg->x; | |||
| yOffset = pg->y; | |||
| const PositionedGlyph& pg = glyphs.getReference (--endIndex); | |||
| xOffset = pg.x; | |||
| yOffset = pg.y; | |||
| glyphs.remove (endIndex); | |||
| ++numDeleted; | |||
| @@ -258,8 +251,8 @@ int GlyphArrangement::insertEllipsis (const Font& font, const float maxXPos, | |||
| for (int i = 3; --i >= 0;) | |||
| { | |||
| glyphs.insert (endIndex++, new PositionedGlyph (font, '.', dotGlyphs.getFirst(), | |||
| xOffset, yOffset, dx, false)); | |||
| glyphs.insert (endIndex++, PositionedGlyph (font, '.', dotGlyphs.getFirst(), | |||
| xOffset, yOffset, dx, false)); | |||
| --numDeleted; | |||
| xOffset += dx; | |||
| @@ -286,33 +279,33 @@ void GlyphArrangement::addJustifiedText (const Font& font, | |||
| { | |||
| int i = lineStartIndex; | |||
| if (glyphs.getUnchecked(i)->getCharacter() != '\n' | |||
| && glyphs.getUnchecked(i)->getCharacter() != '\r') | |||
| if (glyphs.getReference(i).getCharacter() != '\n' | |||
| && glyphs.getReference(i).getCharacter() != '\r') | |||
| ++i; | |||
| const float lineMaxX = glyphs.getUnchecked (lineStartIndex)->getLeft() + maxLineWidth; | |||
| const float lineMaxX = glyphs.getReference (lineStartIndex).getLeft() + maxLineWidth; | |||
| int lastWordBreakIndex = -1; | |||
| while (i < glyphs.size()) | |||
| { | |||
| const PositionedGlyph* pg = glyphs.getUnchecked (i); | |||
| const juce_wchar c = pg->getCharacter(); | |||
| const PositionedGlyph& pg = glyphs.getReference (i); | |||
| const juce_wchar c = pg.getCharacter(); | |||
| if (c == '\r' || c == '\n') | |||
| { | |||
| ++i; | |||
| if (c == '\r' && i < glyphs.size() | |||
| && glyphs.getUnchecked(i)->getCharacter() == '\n') | |||
| && glyphs.getReference(i).getCharacter() == '\n') | |||
| ++i; | |||
| break; | |||
| } | |||
| else if (pg->isWhitespace()) | |||
| else if (pg.isWhitespace()) | |||
| { | |||
| lastWordBreakIndex = i + 1; | |||
| } | |||
| else if (pg->getRight() - 0.0001f >= lineMaxX) | |||
| else if (pg.getRight() - 0.0001f >= lineMaxX) | |||
| { | |||
| if (lastWordBreakIndex >= 0) | |||
| i = lastWordBreakIndex; | |||
| @@ -323,14 +316,14 @@ void GlyphArrangement::addJustifiedText (const Font& font, | |||
| ++i; | |||
| } | |||
| const float currentLineStartX = glyphs.getUnchecked (lineStartIndex)->getLeft(); | |||
| const float currentLineStartX = glyphs.getReference (lineStartIndex).getLeft(); | |||
| float currentLineEndX = currentLineStartX; | |||
| for (int j = i; --j >= lineStartIndex;) | |||
| { | |||
| if (! glyphs.getUnchecked (j)->isWhitespace()) | |||
| if (! glyphs.getReference (j).isWhitespace()) | |||
| { | |||
| currentLineEndX = glyphs.getUnchecked (j)->getRight(); | |||
| currentLineEndX = glyphs.getReference (j).getRight(); | |||
| break; | |||
| } | |||
| } | |||
| @@ -373,19 +366,12 @@ void GlyphArrangement::addFittedText (const Font& f, | |||
| float dy = y - bb.getY(); | |||
| if (layout.testFlags (Justification::verticallyCentred)) | |||
| dy += (height - bb.getHeight()) * 0.5f; | |||
| else if (layout.testFlags (Justification::bottom)) | |||
| dy += height - bb.getHeight(); | |||
| if (layout.testFlags (Justification::verticallyCentred)) dy += (height - bb.getHeight()) * 0.5f; | |||
| else if (layout.testFlags (Justification::bottom)) dy += (height - bb.getHeight()); | |||
| ga.moveRangeOfGlyphs (0, -1, 0.0f, dy); | |||
| glyphs.ensureStorageAllocated (glyphs.size() + ga.glyphs.size()); | |||
| for (int i = 0; i < ga.glyphs.size(); ++i) | |||
| glyphs.add (ga.glyphs.getUnchecked (i)); | |||
| ga.glyphs.clear (false); | |||
| glyphs.addArray (ga.glyphs); | |||
| return; | |||
| } | |||
| @@ -394,8 +380,8 @@ void GlyphArrangement::addFittedText (const Font& f, | |||
| if (glyphs.size() > startIndex) | |||
| { | |||
| float lineWidth = glyphs.getUnchecked (glyphs.size() - 1)->getRight() | |||
| - glyphs.getUnchecked (startIndex)->getLeft(); | |||
| float lineWidth = glyphs.getReference (glyphs.size() - 1).getRight() | |||
| - glyphs.getReference (startIndex).getLeft(); | |||
| if (lineWidth <= 0) | |||
| return; | |||
| @@ -440,8 +426,8 @@ void GlyphArrangement::addFittedText (const Font& f, | |||
| removeRangeOfGlyphs (startIndex, -1); | |||
| addLineOfText (font, txt, x, y); | |||
| lineWidth = glyphs.getUnchecked (glyphs.size() - 1)->getRight() | |||
| - glyphs.getUnchecked (startIndex)->getLeft(); | |||
| lineWidth = glyphs.getReference (glyphs.size() - 1).getRight() | |||
| - glyphs.getReference (startIndex).getLeft(); | |||
| } | |||
| if (numLines > lineWidth / width || newFontHeight < 8.0f) | |||
| @@ -459,7 +445,7 @@ void GlyphArrangement::addFittedText (const Font& f, | |||
| { | |||
| int i = startIndex; | |||
| lastLineStartIndex = i; | |||
| float lineStartX = glyphs.getUnchecked (startIndex)->getLeft(); | |||
| float lineStartX = glyphs.getReference (startIndex).getLeft(); | |||
| if (line == numLines - 1) | |||
| { | |||
| @@ -470,7 +456,7 @@ void GlyphArrangement::addFittedText (const Font& f, | |||
| { | |||
| while (i < glyphs.size()) | |||
| { | |||
| lineWidth = (glyphs.getUnchecked (i)->getRight() - lineStartX); | |||
| lineWidth = (glyphs.getReference (i).getRight() - lineStartX); | |||
| if (lineWidth > widthPerLine) | |||
| { | |||
| @@ -480,10 +466,10 @@ void GlyphArrangement::addFittedText (const Font& f, | |||
| while (i < glyphs.size()) | |||
| { | |||
| if ((glyphs.getUnchecked (i)->getRight() - lineStartX) * minimumHorizontalScale < width) | |||
| if ((glyphs.getReference (i).getRight() - lineStartX) * minimumHorizontalScale < width) | |||
| { | |||
| if (glyphs.getUnchecked (i)->isWhitespace() | |||
| || glyphs.getUnchecked (i)->getCharacter() == '-') | |||
| if (glyphs.getReference (i).isWhitespace() | |||
| || glyphs.getReference (i).getCharacter() == '-') | |||
| { | |||
| ++i; | |||
| break; | |||
| @@ -496,8 +482,8 @@ void GlyphArrangement::addFittedText (const Font& f, | |||
| for (int back = 1; back < jmin (5, i - startIndex - 1); ++back) | |||
| { | |||
| if (glyphs.getUnchecked (i - back)->isWhitespace() | |||
| || glyphs.getUnchecked (i - back)->getCharacter() == '-') | |||
| if (glyphs.getReference (i - back).isWhitespace() | |||
| || glyphs.getReference (i - back).getCharacter() == '-') | |||
| { | |||
| i -= back - 1; | |||
| break; | |||
| @@ -517,12 +503,12 @@ void GlyphArrangement::addFittedText (const Font& f, | |||
| } | |||
| int wsStart = i; | |||
| while (wsStart > 0 && glyphs.getUnchecked (wsStart - 1)->isWhitespace()) | |||
| while (wsStart > 0 && glyphs.getReference (wsStart - 1).isWhitespace()) | |||
| --wsStart; | |||
| int wsEnd = i; | |||
| while (wsEnd < glyphs.size() && glyphs.getUnchecked (wsEnd)->isWhitespace()) | |||
| while (wsEnd < glyphs.size() && glyphs.getReference (wsEnd).isWhitespace()) | |||
| ++wsEnd; | |||
| removeRangeOfGlyphs (wsStart, wsEnd - wsStart); | |||
| @@ -548,8 +534,7 @@ void GlyphArrangement::addFittedText (const Font& f, | |||
| } | |||
| //============================================================================== | |||
| void GlyphArrangement::moveRangeOfGlyphs (int startIndex, int num, | |||
| const float dx, const float dy) | |||
| void GlyphArrangement::moveRangeOfGlyphs (int startIndex, int num, const float dx, const float dy) | |||
| { | |||
| jassert (startIndex >= 0); | |||
| @@ -559,7 +544,7 @@ void GlyphArrangement::moveRangeOfGlyphs (int startIndex, int num, | |||
| num = glyphs.size() - startIndex; | |||
| while (--num >= 0) | |||
| glyphs.getUnchecked (startIndex++)->moveBy (dx, dy); | |||
| glyphs.getReference (startIndex++).moveBy (dx, dy); | |||
| } | |||
| } | |||
| @@ -567,15 +552,15 @@ int GlyphArrangement::fitLineIntoSpace (int start, int numGlyphs, float x, float | |||
| const Justification& justification, float minimumHorizontalScale) | |||
| { | |||
| int numDeleted = 0; | |||
| const float lineStartX = glyphs.getUnchecked (start)->getLeft(); | |||
| float lineWidth = glyphs.getUnchecked (start + numGlyphs - 1)->getRight() - lineStartX; | |||
| const float lineStartX = glyphs.getReference (start).getLeft(); | |||
| float lineWidth = glyphs.getReference (start + numGlyphs - 1).getRight() - lineStartX; | |||
| if (lineWidth > w) | |||
| { | |||
| if (minimumHorizontalScale < 1.0f) | |||
| { | |||
| stretchRangeOfGlyphs (start, numGlyphs, jmax (minimumHorizontalScale, w / lineWidth)); | |||
| lineWidth = glyphs.getUnchecked (start + numGlyphs - 1)->getRight() - lineStartX - 0.5f; | |||
| lineWidth = glyphs.getReference (start + numGlyphs - 1).getRight() - lineStartX - 0.5f; | |||
| } | |||
| if (lineWidth > w) | |||
| @@ -599,15 +584,15 @@ void GlyphArrangement::stretchRangeOfGlyphs (int startIndex, int num, | |||
| if (num > 0) | |||
| { | |||
| const float xAnchor = glyphs.getUnchecked (startIndex)->getLeft(); | |||
| const float xAnchor = glyphs.getReference (startIndex).getLeft(); | |||
| while (--num >= 0) | |||
| { | |||
| PositionedGlyph* const pg = glyphs.getUnchecked (startIndex++); | |||
| PositionedGlyph& pg = glyphs.getReference (startIndex++); | |||
| pg->x = xAnchor + (pg->x - xAnchor) * horizontalScaleFactor; | |||
| pg->font.setHorizontalScale (pg->font.getHorizontalScale() * horizontalScaleFactor); | |||
| pg->w *= horizontalScaleFactor; | |||
| pg.x = xAnchor + (pg.x - xAnchor) * horizontalScaleFactor; | |||
| pg.font.setHorizontalScale (pg.font.getHorizontalScale() * horizontalScaleFactor); | |||
| pg.w *= horizontalScaleFactor; | |||
| } | |||
| } | |||
| } | |||
| @@ -623,10 +608,10 @@ Rectangle<float> GlyphArrangement::getBoundingBox (int startIndex, int num, cons | |||
| while (--num >= 0) | |||
| { | |||
| const PositionedGlyph* const pg = glyphs.getUnchecked (startIndex++); | |||
| const PositionedGlyph& pg = glyphs.getReference (startIndex++); | |||
| if (includeWhitespace || ! pg->isWhitespace()) | |||
| result = result.getUnion (pg->getBounds()); | |||
| if (includeWhitespace || ! pg.isWhitespace()) | |||
| result = result.getUnion (pg.getBounds()); | |||
| } | |||
| return result; | |||
| @@ -667,12 +652,12 @@ void GlyphArrangement::justifyGlyphs (const int startIndex, const int num, | |||
| if (justification.testFlags (Justification::horizontallyJustified)) | |||
| { | |||
| int lineStart = 0; | |||
| float baseY = glyphs.getUnchecked (startIndex)->getBaselineY(); | |||
| float baseY = glyphs.getReference (startIndex).getBaselineY(); | |||
| int i; | |||
| for (i = 0; i < num; ++i) | |||
| { | |||
| const float glyphY = glyphs.getUnchecked (startIndex + i)->getBaselineY(); | |||
| const float glyphY = glyphs.getReference (startIndex + i).getBaselineY(); | |||
| if (glyphY != baseY) | |||
| { | |||
| @@ -692,15 +677,15 @@ void GlyphArrangement::justifyGlyphs (const int startIndex, const int num, | |||
| void GlyphArrangement::spreadOutLine (const int start, const int num, const float targetWidth) | |||
| { | |||
| if (start + num < glyphs.size() | |||
| && glyphs.getUnchecked (start + num - 1)->getCharacter() != '\r' | |||
| && glyphs.getUnchecked (start + num - 1)->getCharacter() != '\n') | |||
| && glyphs.getReference (start + num - 1).getCharacter() != '\r' | |||
| && glyphs.getReference (start + num - 1).getCharacter() != '\n') | |||
| { | |||
| int numSpaces = 0; | |||
| int spacesAtEnd = 0; | |||
| for (int i = 0; i < num; ++i) | |||
| { | |||
| if (glyphs.getUnchecked (start + i)->isWhitespace()) | |||
| if (glyphs.getReference (start + i).isWhitespace()) | |||
| { | |||
| ++spacesAtEnd; | |||
| ++numSpaces; | |||
| @@ -715,8 +700,8 @@ void GlyphArrangement::spreadOutLine (const int start, const int num, const floa | |||
| if (numSpaces > 0) | |||
| { | |||
| const float startX = glyphs.getUnchecked (start)->getLeft(); | |||
| const float endX = glyphs.getUnchecked (start + num - 1 - spacesAtEnd)->getRight(); | |||
| const float startX = glyphs.getReference (start).getLeft(); | |||
| const float endX = glyphs.getReference (start + num - 1 - spacesAtEnd).getRight(); | |||
| const float extraPaddingBetweenWords | |||
| = (targetWidth - (endX - startX)) / (float) numSpaces; | |||
| @@ -725,9 +710,9 @@ void GlyphArrangement::spreadOutLine (const int start, const int num, const floa | |||
| for (int i = 0; i < num; ++i) | |||
| { | |||
| glyphs.getUnchecked (start + i)->moveBy (deltaX, 0.0f); | |||
| glyphs.getReference (start + i).moveBy (deltaX, 0.0f); | |||
| if (glyphs.getUnchecked (start + i)->isWhitespace()) | |||
| if (glyphs.getReference (start + i).isWhitespace()) | |||
| deltaX += extraPaddingBetweenWords; | |||
| } | |||
| } | |||
| @@ -739,22 +724,22 @@ void GlyphArrangement::draw (const Graphics& g) const | |||
| { | |||
| for (int i = 0; i < glyphs.size(); ++i) | |||
| { | |||
| const PositionedGlyph* const pg = glyphs.getUnchecked(i); | |||
| const PositionedGlyph& pg = glyphs.getReference(i); | |||
| if (pg->font.isUnderlined()) | |||
| if (pg.font.isUnderlined()) | |||
| { | |||
| const float lineThickness = (pg->font.getDescent()) * 0.3f; | |||
| const float lineThickness = (pg.font.getDescent()) * 0.3f; | |||
| float nextX = pg->x + pg->w; | |||
| float nextX = pg.x + pg.w; | |||
| if (i < glyphs.size() - 1 && glyphs.getUnchecked (i + 1)->y == pg->y) | |||
| nextX = glyphs.getUnchecked (i + 1)->x; | |||
| if (i < glyphs.size() - 1 && glyphs.getReference (i + 1).y == pg.y) | |||
| nextX = glyphs.getReference (i + 1).x; | |||
| g.fillRect (pg->x, pg->y + lineThickness * 2.0f, | |||
| nextX - pg->x, lineThickness); | |||
| g.fillRect (pg.x, pg.y + lineThickness * 2.0f, | |||
| nextX - pg.x, lineThickness); | |||
| } | |||
| pg->draw (g); | |||
| pg.draw (g); | |||
| } | |||
| } | |||
| @@ -762,39 +747,37 @@ void GlyphArrangement::draw (const Graphics& g, const AffineTransform& transform | |||
| { | |||
| for (int i = 0; i < glyphs.size(); ++i) | |||
| { | |||
| const PositionedGlyph* const pg = glyphs.getUnchecked(i); | |||
| const PositionedGlyph& pg = glyphs.getReference(i); | |||
| if (pg->font.isUnderlined()) | |||
| if (pg.font.isUnderlined()) | |||
| { | |||
| const float lineThickness = (pg->font.getDescent()) * 0.3f; | |||
| const float lineThickness = (pg.font.getDescent()) * 0.3f; | |||
| float nextX = pg->x + pg->w; | |||
| float nextX = pg.x + pg.w; | |||
| if (i < glyphs.size() - 1 && glyphs.getUnchecked (i + 1)->y == pg->y) | |||
| nextX = glyphs.getUnchecked (i + 1)->x; | |||
| if (i < glyphs.size() - 1 && glyphs.getReference (i + 1).y == pg.y) | |||
| nextX = glyphs.getReference (i + 1).x; | |||
| Path p; | |||
| p.addLineSegment (Line<float> (pg->x, pg->y + lineThickness * 2.0f, | |||
| nextX, pg->y + lineThickness * 2.0f), | |||
| lineThickness); | |||
| p.addLineSegment (Line<float> (pg.x, pg.y + lineThickness * 2.0f, | |||
| nextX, pg.y + lineThickness * 2.0f), lineThickness); | |||
| g.fillPath (p, transform); | |||
| } | |||
| pg->draw (g, transform); | |||
| pg.draw (g, transform); | |||
| } | |||
| } | |||
| void GlyphArrangement::createPath (Path& path) const | |||
| { | |||
| for (int i = 0; i < glyphs.size(); ++i) | |||
| glyphs.getUnchecked (i)->createPath (path); | |||
| glyphs.getReference (i).createPath (path); | |||
| } | |||
| int GlyphArrangement::findGlyphIndexAt (float x, float y) const | |||
| int GlyphArrangement::findGlyphIndexAt (const float x, const float y) const | |||
| { | |||
| for (int i = 0; i < glyphs.size(); ++i) | |||
| if (glyphs.getUnchecked (i)->hitTest (x, y)) | |||
| if (glyphs.getReference (i).hitTest (x, y)) | |||
| return i; | |||
| return -1; | |||
| @@ -44,6 +44,7 @@ class JUCE_API PositionedGlyph | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| PositionedGlyph() noexcept; | |||
| PositionedGlyph (const Font& font, juce_wchar character, int glyphNumber, | |||
| float anchorX, float baselineY, float width, bool isWhitespace); | |||
| @@ -140,7 +141,7 @@ public: | |||
| careful not to pass an out-of-range index here, as it | |||
| doesn't do any bounds-checking. | |||
| */ | |||
| PositionedGlyph& getGlyph (int index) const; | |||
| PositionedGlyph& getGlyph (int index) const noexcept; | |||
| //============================================================================== | |||
| /** Clears all text from the arrangement and resets it. | |||
| @@ -301,7 +302,7 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| OwnedArray <PositionedGlyph> glyphs; | |||
| Array <PositionedGlyph> glyphs; | |||
| int insertEllipsis (const Font&, float maxXPos, int startIndex, int endIndex); | |||
| int fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font&, | |||
| @@ -197,9 +197,9 @@ void TextLayout::addLine (Line* line) | |||
| void TextLayout::draw (Graphics& g, const Rectangle<float>& area) const | |||
| { | |||
| const Point<float> origin (justification.appliedToRectangle (Rectangle<float> (0, 0, width, getHeight()), area).getPosition()); | |||
| const Point<float> origin (justification.appliedToRectangle (Rectangle<float> (width, getHeight()), area).getPosition()); | |||
| LowLevelGraphicsContext& context = *g.getInternalContext(); | |||
| LowLevelGraphicsContext& context = g.getInternalContext(); | |||
| for (int i = 0; i < getNumLines(); ++i) | |||
| { | |||
| @@ -1118,7 +1118,7 @@ struct DefaultFontNames | |||
| #else | |||
| : defaultSans ("Lucida Grande"), | |||
| defaultSerif ("Times New Roman"), | |||
| defaultFixed ("Monaco"), | |||
| defaultFixed ("Menlo"), | |||
| #endif | |||
| defaultFallback ("Arial Unicode MS") | |||
| { | |||
| @@ -720,18 +720,18 @@ public: | |||
| { | |||
| Graphics imG (image); | |||
| LowLevelGraphicsContext* const lg = imG.getInternalContext(); | |||
| LowLevelGraphicsContext& lg = imG.getInternalContext(); | |||
| for (RectangleList::Iterator i (validArea); i.next();) | |||
| lg->excludeClipRectangle (*i.getRectangle()); | |||
| lg.excludeClipRectangle (*i.getRectangle()); | |||
| if (! lg->isClipEmpty()) | |||
| if (! lg.isClipEmpty()) | |||
| { | |||
| if (! owner.isOpaque()) | |||
| { | |||
| lg->setFill (Colours::transparentBlack); | |||
| lg->fillRect (bounds, true); | |||
| lg->setFill (Colours::black); | |||
| lg.setFill (Colours::transparentBlack); | |||
| lg.fillRect (bounds, true); | |||
| lg.setFill (Colours::black); | |||
| } | |||
| owner.paintEntireComponent (imG, true); | |||
| @@ -1946,7 +1946,7 @@ void Component::paintEntireComponent (Graphics& g, const bool ignoreAlphaLevel) | |||
| if (effect != nullptr) | |||
| { | |||
| const float scale = g.getInternalContext()->getTargetDeviceScaleFactor(); | |||
| const float scale = g.getInternalContext().getTargetDeviceScaleFactor(); | |||
| Image effectImage (flags.opaqueFlag ? Image::RGB : Image::ARGB, | |||
| (int) (scale * getWidth()), (int) (scale * getHeight()), ! flags.opaqueFlag); | |||
| @@ -89,9 +89,7 @@ public: | |||
| virtual void setIndex (int newIndex); | |||
| /** Returns the index of the item that should currently be shown. | |||
| This is the index of the item in the choices StringArray that will be | |||
| shown. | |||
| This is the index of the item in the choices StringArray that will be shown. | |||
| */ | |||
| virtual int getIndex() const; | |||
| @@ -102,8 +100,6 @@ public: | |||
| //============================================================================== | |||
| /** @internal */ | |||
| void refresh(); | |||
| /** @internal */ | |||
| void comboBoxChanged (ComboBox*); | |||
| protected: | |||
| /** The list of options that will be shown in the combo box. | |||
| @@ -120,6 +116,7 @@ private: | |||
| class RemapperValueSource; | |||
| void createComboBox(); | |||
| void comboBoxChanged (ComboBox*); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChoicePropertyComponent); | |||
| }; | |||
| @@ -32,14 +32,14 @@ public: | |||
| bool update (CodeDocument& document, int lineNum, | |||
| CodeDocument::Iterator& source, | |||
| CodeTokeniser* analyser, const int spacesPerTab, | |||
| CodeTokeniser* tokeniser, const int spacesPerTab, | |||
| const CodeDocument::Position& selectionStart, | |||
| const CodeDocument::Position& selectionEnd) | |||
| { | |||
| Array <SyntaxToken> newTokens; | |||
| newTokens.ensureStorageAllocated (8); | |||
| if (analyser == nullptr) | |||
| if (tokeniser == nullptr) | |||
| { | |||
| newTokens.add (SyntaxToken (document.getLine (lineNum), -1)); | |||
| } | |||
| @@ -47,7 +47,7 @@ public: | |||
| { | |||
| const CodeDocument::Position pos (&document, lineNum, 0); | |||
| createTokens (pos.getPosition(), pos.getLineText(), | |||
| source, analyser, newTokens); | |||
| source, *tokeniser, newTokens); | |||
| } | |||
| replaceTabsWithSpaces (newTokens, spacesPerTab); | |||
| @@ -96,7 +96,7 @@ public: | |||
| } | |||
| void draw (CodeEditorComponent& owner, Graphics& g, const Font& font, | |||
| float x, const int y, const int baselineOffset, const int lineHeight, | |||
| float x, const float rightEdge, const int y, const int baselineOffset, const int lineHeight, | |||
| const Colour& highlightColour) const | |||
| { | |||
| if (highlightColumnStart < highlightColumnEnd) | |||
| @@ -106,19 +106,25 @@ public: | |||
| roundToInt ((highlightColumnEnd - highlightColumnStart) * owner.getCharWidth()), lineHeight); | |||
| } | |||
| int lastType = std::numeric_limits<int>::min(); | |||
| const float baselineY = (float) (y + baselineOffset); | |||
| Colour lastColour (0x00000001); | |||
| GlyphArrangement ga; | |||
| for (int i = 0; i < tokens.size(); ++i) | |||
| { | |||
| SyntaxToken& token = tokens.getReference(i); | |||
| if (lastType != token.tokenType) | |||
| const Colour newColour (owner.getColourForTokenType (token.tokenType)); | |||
| if (lastColour != newColour) | |||
| { | |||
| lastType = token.tokenType; | |||
| g.setColour (owner.getColourForTokenType (lastType)); | |||
| ga.draw (g); | |||
| ga.clear(); | |||
| lastColour = newColour; | |||
| g.setColour (newColour); | |||
| } | |||
| g.drawSingleLineText (token.text, roundToInt (x), y + baselineOffset); | |||
| ga.addCurtailedLineOfText (font, token.text, x, baselineY, rightEdge - x, false); | |||
| if (i < tokens.size() - 1) | |||
| { | |||
| @@ -126,8 +132,13 @@ public: | |||
| token.width = font.getStringWidthFloat (token.text); | |||
| x += token.width; | |||
| if (x > rightEdge) | |||
| break; | |||
| } | |||
| } | |||
| ga.draw (g); | |||
| } | |||
| private: | |||
| @@ -153,7 +164,7 @@ private: | |||
| static void createTokens (int startPosition, const String& lineText, | |||
| CodeDocument::Iterator& source, | |||
| CodeTokeniser* analyser, | |||
| CodeTokeniser& tokeniser, | |||
| Array <SyntaxToken>& newTokens) | |||
| { | |||
| CodeDocument::Iterator lastIterator (source); | |||
| @@ -161,7 +172,7 @@ private: | |||
| for (;;) | |||
| { | |||
| int tokenType = analyser->readNextToken (source); | |||
| int tokenType = tokeniser.readNextToken (source); | |||
| int tokenStart = lastIterator.getPosition(); | |||
| int tokenEnd = source.getPosition(); | |||
| @@ -263,8 +274,8 @@ public: | |||
| const int firstLineToDraw = jmax (0, clip.getY() / lineHeight); | |||
| const int lastLineToDraw = jmin (editor.lines.size(), clip.getBottom() / lineHeight + 1); | |||
| const Font lineNumberFont (editor.getFont().withHeight (lineHeight * 0.8f)); | |||
| const float y = (lineHeight - lineNumberFont.getHeight()) / 2.0f + lineNumberFont.getAscent(); | |||
| const Font lineNumberFont (editor.getFont().withHeight (jmin (13.0f, lineHeight * 0.8f))); | |||
| const float y = lineHeight - editor.getFont().getDescent(); | |||
| const float w = getWidth() - 2.0f; | |||
| GlyphArrangement ga; | |||
| @@ -439,12 +450,12 @@ void CodeEditorComponent::paint (Graphics& g) | |||
| const Rectangle<int> clip (g.getClipBounds()); | |||
| const int firstLineToDraw = jmax (0, clip.getY() / lineHeight); | |||
| const int lastLineToDraw = jmin (lines.size(), clip.getBottom() / lineHeight + 1); | |||
| const float x = (float) (gutter - xOffset * charWidth); | |||
| const float rightEdge = (float) getWidth(); | |||
| for (int i = firstLineToDraw; i < lastLineToDraw; ++i) | |||
| lines.getUnchecked(i)->draw (*this, g, font, | |||
| (float) (gutter - xOffset * charWidth), | |||
| lineHeight * i, baselineOffset, lineHeight, | |||
| highlightColour); | |||
| lines.getUnchecked(i)->draw (*this, g, font, x, rightEdge, lineHeight * i, | |||
| baselineOffset, lineHeight, highlightColour); | |||
| } | |||
| void CodeEditorComponent::setScrollbarThickness (const int thickness) | |||
| @@ -488,10 +499,8 @@ void CodeEditorComponent::rebuildLineTokens() | |||
| for (int i = 0; i < numNeeded; ++i) | |||
| { | |||
| CodeEditorLine* const line = lines.getUnchecked(i); | |||
| if (line->update (document, firstLineOnScreen + i, source, codeTokeniser, spacesPerTab, | |||
| selectionStart, selectionEnd)) | |||
| if (lines.getUnchecked(i)->update (document, firstLineOnScreen + i, source, codeTokeniser, | |||
| spacesPerTab, selectionStart, selectionEnd)) | |||
| { | |||
| minLineToRepaint = jmin (minLineToRepaint, i); | |||
| maxLineToRepaint = jmax (maxLineToRepaint, i); | |||
| @@ -1346,14 +1355,14 @@ void CodeEditorComponent::updateCachedIterators (int maxLineNum) | |||
| { | |||
| for (;;) | |||
| { | |||
| CodeDocument::Iterator* const last = cachedIterators.getLast(); | |||
| CodeDocument::Iterator& last = *cachedIterators.getLast(); | |||
| if (last->getLine() >= maxLineNum) | |||
| if (last.getLine() >= maxLineNum) | |||
| break; | |||
| CodeDocument::Iterator* t = new CodeDocument::Iterator (*last); | |||
| CodeDocument::Iterator* t = new CodeDocument::Iterator (last); | |||
| cachedIterators.add (t); | |||
| const int targetLine = last->getLine() + linesBetweenCachedSources; | |||
| const int targetLine = last.getLine() + linesBetweenCachedSources; | |||
| for (;;) | |||
| { | |||
| @@ -1375,10 +1384,10 @@ void CodeEditorComponent::getIteratorForPosition (int position, CodeDocument::It | |||
| { | |||
| for (int i = cachedIterators.size(); --i >= 0;) | |||
| { | |||
| CodeDocument::Iterator* t = cachedIterators.getUnchecked (i); | |||
| if (t->getPosition() <= position) | |||
| const CodeDocument::Iterator& t = *cachedIterators.getUnchecked (i); | |||
| if (t.getPosition() <= position) | |||
| { | |||
| source = *t; | |||
| source = t; | |||
| break; | |||
| } | |||
| } | |||