| @@ -567,7 +567,7 @@ static void createTabTextLayout (const TabBarButton& button, const Rectangle<int | |||||
| textLayout.createLayout (s, (float) textArea.getWidth()); | textLayout.createLayout (s, (float) textArea.getWidth()); | ||||
| } | } | ||||
| static Colour getTabBackgroundColour (TabBarButton& button) | |||||
| Colour IntrojucerLookAndFeel::getTabBackgroundColour (TabBarButton& button) | |||||
| { | { | ||||
| const Colour bkg (button.findColour (mainBackgroundColourId).contrasting (0.15f)); | const Colour bkg (button.findColour (mainBackgroundColourId).contrasting (0.15f)); | ||||
| @@ -580,6 +580,7 @@ static Colour getTabBackgroundColour (TabBarButton& button) | |||||
| void IntrojucerLookAndFeel::drawTabButton (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown) | void IntrojucerLookAndFeel::drawTabButton (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown) | ||||
| { | { | ||||
| const Rectangle<int> activeArea (button.getActiveArea()); | const Rectangle<int> activeArea (button.getActiveArea()); | ||||
| const Colour bkg (getTabBackgroundColour (button)); | const Colour bkg (getTabBackgroundColour (button)); | ||||
| g.setGradientFill (ColourGradient (bkg.brighter (0.1f), 0, (float) activeArea.getY(), | g.setGradientFill (ColourGradient (bkg.brighter (0.1f), 0, (float) activeArea.getY(), | ||||
| @@ -89,6 +89,7 @@ public: | |||||
| int getTabButtonOverlap (int tabDepth); | int getTabButtonOverlap (int tabDepth); | ||||
| int getTabButtonSpaceAroundImage(); | int getTabButtonSpaceAroundImage(); | ||||
| int getTabButtonBestWidth (TabBarButton& button, int tabDepth); | int getTabButtonBestWidth (TabBarButton& button, int tabDepth); | ||||
| static Colour getTabBackgroundColour (TabBarButton& button); | |||||
| void drawTabButton (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown); | void drawTabButton (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown); | ||||
| Rectangle<int> getTabButtonExtraComponentBounds (const TabBarButton& button, Rectangle<int>& textArea, Component& comp); | Rectangle<int> getTabButtonExtraComponentBounds (const TabBarButton& button, Rectangle<int>& textArea, Component& comp); | ||||
| @@ -46,8 +46,7 @@ CodeDocument& SourceCodeDocument::getCodeDocument() | |||||
| Component* SourceCodeDocument::createEditor() | Component* SourceCodeDocument::createEditor() | ||||
| { | { | ||||
| SourceCodeEditor* e = new SourceCodeEditor (this); | |||||
| e->createEditor (getCodeDocument()); | |||||
| SourceCodeEditor* e = new SourceCodeEditor (this, getCodeDocument()); | |||||
| applyLastState (*(e->editor)); | applyLastState (*(e->editor)); | ||||
| return e; | return e; | ||||
| } | } | ||||
| @@ -114,9 +113,21 @@ void SourceCodeDocument::applyLastState (CodeEditorComponent& editor) const | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| SourceCodeEditor::SourceCodeEditor (OpenDocumentManager::Document* doc) | |||||
| SourceCodeEditor::SourceCodeEditor (OpenDocumentManager::Document* doc, CodeDocument& codeDocument) | |||||
| : DocumentEditorComponent (doc) | : DocumentEditorComponent (doc) | ||||
| { | { | ||||
| setOpaque (true); | |||||
| if (document->getFile().hasFileExtension (sourceOrHeaderFileExtensions)) | |||||
| setEditor (new CppCodeEditorComponent (document->getFile(), codeDocument)); | |||||
| else | |||||
| setEditor (new GenericCodeEditorComponent (document->getFile(), codeDocument, nullptr)); | |||||
| } | |||||
| SourceCodeEditor::SourceCodeEditor (OpenDocumentManager::Document* doc, CodeEditorComponent* ed) | |||||
| : DocumentEditorComponent (doc) | |||||
| { | |||||
| setEditor (ed); | |||||
| } | } | ||||
| SourceCodeEditor::~SourceCodeEditor() | SourceCodeEditor::~SourceCodeEditor() | ||||
| @@ -130,14 +141,6 @@ SourceCodeEditor::~SourceCodeEditor() | |||||
| doc->updateLastState (*editor); | doc->updateLastState (*editor); | ||||
| } | } | ||||
| void SourceCodeEditor::createEditor (CodeDocument& codeDocument) | |||||
| { | |||||
| if (document->getFile().hasFileExtension (sourceOrHeaderFileExtensions)) | |||||
| setEditor (new CppCodeEditorComponent (document->getFile(), codeDocument)); | |||||
| else | |||||
| setEditor (new GenericCodeEditorComponent (document->getFile(), codeDocument, nullptr)); | |||||
| } | |||||
| void SourceCodeEditor::setEditor (CodeEditorComponent* newEditor) | void SourceCodeEditor::setEditor (CodeEditorComponent* newEditor) | ||||
| { | { | ||||
| if (editor != nullptr) | if (editor != nullptr) | ||||
| @@ -141,12 +141,10 @@ class SourceCodeEditor : public DocumentEditorComponent, | |||||
| private CodeDocument::Listener | private CodeDocument::Listener | ||||
| { | { | ||||
| public: | public: | ||||
| SourceCodeEditor (OpenDocumentManager::Document* document); | |||||
| SourceCodeEditor (OpenDocumentManager::Document* document, CodeDocument&); | |||||
| SourceCodeEditor (OpenDocumentManager::Document* document, CodeEditorComponent*); | |||||
| ~SourceCodeEditor(); | ~SourceCodeEditor(); | ||||
| void createEditor (CodeDocument& codeDocument); | |||||
| void setEditor (CodeEditorComponent*); | |||||
| void scrollToKeepRangeOnScreen (Range<int> range); | void scrollToKeepRangeOnScreen (Range<int> range); | ||||
| void highlight (Range<int> range, bool cursorAtStart); | void highlight (Range<int> range, bool cursorAtStart); | ||||
| @@ -165,6 +163,7 @@ private: | |||||
| void codeDocumentTextInserted (const String&, int); | void codeDocumentTextInserted (const String&, int); | ||||
| void codeDocumentTextDeleted (int, int); | void codeDocumentTextDeleted (int, int); | ||||
| void setEditor (CodeEditorComponent*); | |||||
| void updateColourScheme(); | void updateColourScheme(); | ||||
| void checkSaveState(); | void checkSaveState(); | ||||
| @@ -329,9 +329,9 @@ JucerDocumentEditor::JucerDocumentEditor (JucerDocument* const doc) | |||||
| tabbedComponent.addTab ("Resources", tabColour, new ResourceEditorPanel (*document), true); | tabbedComponent.addTab ("Resources", tabColour, new ResourceEditorPanel (*document), true); | ||||
| SourceCodeEditor* codeEditor = new SourceCodeEditor (&document->getCppDocument()); | |||||
| codeEditor->setEditor (new CppCodeEditorComponent (document->getCppFile(), | |||||
| document->getCppDocument().getCodeDocument())); | |||||
| SourceCodeEditor* codeEditor = new SourceCodeEditor (&document->getCppDocument(), | |||||
| new CppCodeEditorComponent (document->getCppFile(), | |||||
| document->getCppDocument().getCodeDocument())); | |||||
| tabbedComponent.addTab ("Code", tabColour, codeEditor, true); | tabbedComponent.addTab ("Code", tabColour, codeEditor, true); | ||||
| @@ -39,6 +39,8 @@ extern "C" | |||||
| } | } | ||||
| #endif | #endif | ||||
| static CTFontRef getCTFontFromTypeface (const Font& f); | |||||
| namespace CoreTextTypeLayout | namespace CoreTextTypeLayout | ||||
| { | { | ||||
| static String findBestAvailableStyle (const Font& font, CGAffineTransform& requiredTransform) | static String findBestAvailableStyle (const Font& font, CGAffineTransform& requiredTransform) | ||||
| @@ -187,6 +189,18 @@ namespace CoreTextTypeLayout | |||||
| HeapBlock<CGPoint> local; | HeapBlock<CGPoint> local; | ||||
| }; | }; | ||||
| static CTFontRef getOrCreateFont (const Font& f) | |||||
| { | |||||
| if (CTFontRef ctf = getCTFontFromTypeface (f)) | |||||
| { | |||||
| CFRetain (ctf); | |||||
| return ctf; | |||||
| } | |||||
| CGAffineTransform transform; | |||||
| return createCTFont (f, referenceFontSize, transform); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| static CFAttributedStringRef createCFAttributedString (const AttributedString& text) | static CFAttributedStringRef createCFAttributedString (const AttributedString& text) | ||||
| { | { | ||||
| @@ -213,13 +227,14 @@ namespace CoreTextTypeLayout | |||||
| if (const Font* const f = attr->getFont()) | if (const Font* const f = attr->getFont()) | ||||
| { | { | ||||
| CGAffineTransform transform; | |||||
| CTFontRef ctFontRef = createCTFont (*f, referenceFontSize, transform); | |||||
| ctFontRef = getFontWithPointSize (ctFontRef, f->getHeight() * getHeightToPointsFactor (ctFontRef)); | |||||
| if (CTFontRef ctFontRef = getOrCreateFont (*f)) | |||||
| { | |||||
| ctFontRef = getFontWithPointSize (ctFontRef, f->getHeight() * getHeightToPointsFactor (ctFontRef)); | |||||
| CFAttributedStringSetAttribute (attribString, CFRangeMake (range.getStart(), range.getLength()), | |||||
| kCTFontAttributeName, ctFontRef); | |||||
| CFRelease (ctFontRef); | |||||
| CFAttributedStringSetAttribute (attribString, CFRangeMake (range.getStart(), range.getLength()), | |||||
| kCTFontAttributeName, ctFontRef); | |||||
| CFRelease (ctFontRef); | |||||
| } | |||||
| } | } | ||||
| if (const Colour* const col = attr->getColour()) | if (const Colour* const col = attr->getColour()) | ||||
| @@ -416,11 +431,11 @@ class OSXTypeface : public Typeface | |||||
| public: | public: | ||||
| OSXTypeface (const Font& font) | OSXTypeface (const Font& font) | ||||
| : Typeface (font.getTypefaceName(), | : Typeface (font.getTypefaceName(), | ||||
| font.getTypefaceStyle()), | |||||
| font.getTypefaceStyle()), | |||||
| fontRef (nullptr), | fontRef (nullptr), | ||||
| ctFontRef (nullptr), | |||||
| fontHeightToPointsFactor (1.0f), | fontHeightToPointsFactor (1.0f), | ||||
| renderingTransform (CGAffineTransformIdentity), | renderingTransform (CGAffineTransformIdentity), | ||||
| ctFontRef (nullptr), | |||||
| attributedStringAtts (nullptr), | attributedStringAtts (nullptr), | ||||
| ascent (0.0f), | ascent (0.0f), | ||||
| unitsToHeightScaleFactor (0.0f) | unitsToHeightScaleFactor (0.0f) | ||||
| @@ -566,12 +581,12 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| CGFontRef fontRef; | CGFontRef fontRef; | ||||
| CTFontRef ctFontRef; | |||||
| float fontHeightToPointsFactor; | float fontHeightToPointsFactor; | ||||
| CGAffineTransform renderingTransform; | CGAffineTransform renderingTransform; | ||||
| private: | private: | ||||
| CTFontRef ctFontRef; | |||||
| CFDictionaryRef attributedStringAtts; | CFDictionaryRef attributedStringAtts; | ||||
| float ascent, unitsToHeightScaleFactor; | float ascent, unitsToHeightScaleFactor; | ||||
| AffineTransform pathTransform; | AffineTransform pathTransform; | ||||
| @@ -598,6 +613,15 @@ private: | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSXTypeface) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSXTypeface) | ||||
| }; | }; | ||||
| CTFontRef getCTFontFromTypeface (const Font& f) | |||||
| { | |||||
| if (OSXTypeface* tf = dynamic_cast <OSXTypeface*> (f.getTypeface())) | |||||
| return tf->ctFontRef; | |||||
| return 0; | |||||
| } | |||||
| StringArray Font::findAllTypefaceNames() | StringArray Font::findAllTypefaceNames() | ||||
| { | { | ||||
| StringArray names; | StringArray names; | ||||
| @@ -158,28 +158,21 @@ void DrawableText::recalculateCoordinates (Expression::Scope* scope) | |||||
| repaint(); | repaint(); | ||||
| } | } | ||||
| const AffineTransform DrawableText::getArrangementAndTransform (GlyphArrangement& glyphs) const | |||||
| { | |||||
| const float w = Line<float> (resolvedPoints[0], resolvedPoints[1]).getLength(); | |||||
| const float h = Line<float> (resolvedPoints[0], resolvedPoints[2]).getLength(); | |||||
| glyphs.addFittedText (scaledFont, text, 0, 0, w, h, justification, 0x100000); | |||||
| return AffineTransform::fromTargetPoints (0, 0, resolvedPoints[0].x, resolvedPoints[0].y, | |||||
| w, 0, resolvedPoints[1].x, resolvedPoints[1].y, | |||||
| 0, h, resolvedPoints[2].x, resolvedPoints[2].y); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| void DrawableText::paint (Graphics& g) | void DrawableText::paint (Graphics& g) | ||||
| { | { | ||||
| transformContextToCorrectOrigin (g); | transformContextToCorrectOrigin (g); | ||||
| const float w = Line<float> (resolvedPoints[0], resolvedPoints[1]).getLength(); | |||||
| const float h = Line<float> (resolvedPoints[0], resolvedPoints[2]).getLength(); | |||||
| g.addTransform (AffineTransform::fromTargetPoints (0, 0, resolvedPoints[0].x, resolvedPoints[0].y, | |||||
| w, 0, resolvedPoints[1].x, resolvedPoints[1].y, | |||||
| 0, h, resolvedPoints[2].x, resolvedPoints[2].y)); | |||||
| g.setFont (scaledFont); | |||||
| g.setColour (colour); | g.setColour (colour); | ||||
| GlyphArrangement ga; | |||||
| const AffineTransform transform (getArrangementAndTransform (ga)); | |||||
| ga.draw (g, transform); | |||||
| g.drawFittedText (text, Rectangle<int> (w, h), justification, 0x100000); | |||||
| } | } | ||||
| Rectangle<float> DrawableText::getDrawableBounds() const | Rectangle<float> DrawableText::getDrawableBounds() const | ||||
| @@ -149,7 +149,6 @@ private: | |||||
| bool registerCoordinates (RelativeCoordinatePositionerBase&); | bool registerCoordinates (RelativeCoordinatePositionerBase&); | ||||
| void recalculateCoordinates (Expression::Scope*); | void recalculateCoordinates (Expression::Scope*); | ||||
| void refreshBounds(); | void refreshBounds(); | ||||
| const AffineTransform getArrangementAndTransform (GlyphArrangement& glyphs) const; | |||||
| DrawableText& operator= (const DrawableText&); | DrawableText& operator= (const DrawableText&); | ||||
| JUCE_LEAK_DETECTOR (DrawableText) | JUCE_LEAK_DETECTOR (DrawableText) | ||||
| @@ -81,8 +81,7 @@ public: | |||||
| } | } | ||||
| void draw (CodeEditorComponent& owner, Graphics& g, const Font& fontToUse, | void draw (CodeEditorComponent& owner, Graphics& g, const Font& fontToUse, | ||||
| const float leftClip, const float rightClip, | |||||
| const float x, const int y, const int baselineOffset, | |||||
| const float rightClip, const float x, const int y, | |||||
| const int lineH, const float characterWidth, | const int lineH, const float characterWidth, | ||||
| const Colour highlightColour) const | const Colour highlightColour) const | ||||
| { | { | ||||
| @@ -93,9 +92,11 @@ public: | |||||
| roundToInt ((highlightColumnEnd - highlightColumnStart) * characterWidth), lineH); | roundToInt ((highlightColumnEnd - highlightColumnStart) * characterWidth), lineH); | ||||
| } | } | ||||
| const float baselineY = (float) (y + baselineOffset); | |||||
| Colour lastColour (0x00000001); | Colour lastColour (0x00000001); | ||||
| GlyphArrangement ga; | |||||
| AttributedString as; | |||||
| as.setJustification (Justification::centredLeft); | |||||
| int column = 0; | int column = 0; | ||||
| for (int i = 0; i < tokens.size(); ++i) | for (int i = 0; i < tokens.size(); ++i) | ||||
| @@ -104,26 +105,12 @@ public: | |||||
| if (tokenX > rightClip) | if (tokenX > rightClip) | ||||
| break; | break; | ||||
| SyntaxToken& token = tokens.getReference(i); | |||||
| const Colour newColour (owner.getColourForTokenType (token.tokenType)); | |||||
| if (lastColour != newColour) | |||||
| { | |||||
| ga.draw (g); | |||||
| ga.clear(); | |||||
| lastColour = newColour; | |||||
| g.setColour (newColour); | |||||
| } | |||||
| const SyntaxToken& token = tokens.getReference(i); | |||||
| as.append (token.text, fontToUse, owner.getColourForTokenType (token.tokenType)); | |||||
| column += token.length; | column += token.length; | ||||
| if (x + column * characterWidth >= leftClip) | |||||
| ga.addCurtailedLineOfText (fontToUse, token.text, tokenX, baselineY, | |||||
| (rightClip - tokenX) + characterWidth, false); | |||||
| } | } | ||||
| ga.draw (g); | |||||
| as.draw (g, Rectangle<int> (x, y, 10000, lineH).toFloat()); | |||||
| } | } | ||||
| private: | private: | ||||
| @@ -484,20 +471,18 @@ void CodeEditorComponent::paint (Graphics& g) | |||||
| g.reduceClipRegion (gutterSize, 0, verticalScrollBar.getX() - gutterSize, horizontalScrollBar.getY()); | g.reduceClipRegion (gutterSize, 0, verticalScrollBar.getX() - gutterSize, horizontalScrollBar.getY()); | ||||
| g.setFont (font); | g.setFont (font); | ||||
| const int baselineOffset = (int) font.getAscent(); | |||||
| const Colour highlightColour (findColour (CodeEditorComponent::highlightColourId)); | const Colour highlightColour (findColour (CodeEditorComponent::highlightColourId)); | ||||
| const Rectangle<int> clip (g.getClipBounds()); | const Rectangle<int> clip (g.getClipBounds()); | ||||
| const int firstLineToDraw = jmax (0, clip.getY() / lineHeight); | const int firstLineToDraw = jmax (0, clip.getY() / lineHeight); | ||||
| const int lastLineToDraw = jmin (lines.size(), clip.getBottom() / lineHeight + 1); | const int lastLineToDraw = jmin (lines.size(), clip.getBottom() / lineHeight + 1); | ||||
| const float x = (float) (gutterSize - xOffset * charWidth); | const float x = (float) (gutterSize - xOffset * charWidth); | ||||
| const float leftClip = (float) clip.getX(); | |||||
| const float rightClip = (float) clip.getRight(); | const float rightClip = (float) clip.getRight(); | ||||
| for (int i = firstLineToDraw; i < lastLineToDraw; ++i) | for (int i = firstLineToDraw; i < lastLineToDraw; ++i) | ||||
| lines.getUnchecked(i)->draw (*this, g, font, leftClip, rightClip, | |||||
| x, lineHeight * i, baselineOffset, | |||||
| lineHeight, charWidth, highlightColour); | |||||
| lines.getUnchecked(i)->draw (*this, g, font, rightClip, | |||||
| x, lineHeight * i, lineHeight, | |||||
| charWidth, highlightColour); | |||||
| } | } | ||||
| void CodeEditorComponent::setScrollbarThickness (const int thickness) | void CodeEditorComponent::setScrollbarThickness (const int thickness) | ||||