diff --git a/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementText.h b/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementText.h index 5d7be98635..5d17a69e4f 100644 --- a/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementText.h +++ b/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementText.h @@ -1,673 +1,673 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2020 - Raw Material Software Limited - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 22nd April 2020). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -#pragma once - -#include "jucer_ColouredElement.h" -#include "../Properties/jucer_FontPropertyComponent.h" -#include "../Properties/jucer_JustificationProperty.h" - -//============================================================================== -class PaintElementText : public ColouredElement -{ -public: - PaintElementText (PaintRoutine* pr) - : ColouredElement (pr, "Text", false, false), - text ("Your text goes here"), - font (15.0f), - typefaceName (FontPropertyComponent::getDefaultFont()), - justification (Justification::centred) - { - fillType.colour = Colours::black; - position.rect.setWidth (200); - position.rect.setHeight (30); - } - - //============================================================================== - void draw (Graphics& g, const ComponentLayout* layout, const Rectangle& parentArea) override - { - fillType.setFillType (g, getDocument(), parentArea); - - font = FontPropertyComponent::applyNameToFont (typefaceName, font); - g.setFont (font); - - g.drawText (replaceStringTranslations (text, owner->getDocument()), - position.getRectangle (parentArea, layout), justification, true); - } - - static String replaceStringTranslations (String s, JucerDocument* document) - { - s = s.replace ("%%getName()%%", document->getComponentName()); - s = s.replace ("%%getButtonText()%%", document->getComponentName()); - return s; - } - - void getEditableProperties (Array& props, bool multipleSelected) override - { - ColouredElement::getEditableProperties (props, multipleSelected); - - if (multipleSelected) - return; - - props.add (new TextProperty (this)); - props.add (new FontNameProperty (this)); - props.add (new FontStyleProperty (this)); - props.add (new FontSizeProperty (this)); - props.add (new FontKerningProperty (this)); - props.add (new TextJustificationProperty (this)); - props.add (new TextToPathProperty (this)); - } - - void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) override - { - if (! fillType.isInvisible()) - { - String x, y, w, h, r; - positionToCode (position, code.document->getComponentLayout(), x, y, w, h); - r << "{\n" - << " int x = " << x << ", y = " << y << ", width = " << w << ", height = " << h << ";\n" - << " String text (" << quotedString (text, code.shouldUseTransMacro()) << ");\n" - << " " << fillType.generateVariablesCode ("fill") - << " //[UserPaintCustomArguments] Customize the painting arguments here..\n" - << customPaintCode - << " //[/UserPaintCustomArguments]\n" - << " "; - fillType.fillInGeneratedCode ("fill", position, code, r); - r << " g.setFont (" << FontPropertyComponent::getCompleteFontCode (font, typefaceName) << ");\n" - << " g.drawText (text, x, y, width, height,\n" - << " " << CodeHelpers::justificationToCode (justification) << ", true);\n" - << "}\n\n"; - - paintMethodCode += r; - } - } - - void applyCustomPaintSnippets (StringArray& snippets) override - { - customPaintCode.clear(); - - if (! snippets.isEmpty() && ! fillType.isInvisible()) - { - customPaintCode = snippets[0]; - snippets.remove (0); - } - } - - static const char* getTagName() noexcept { return "TEXT"; } - - XmlElement* createXml() const override - { - XmlElement* e = new XmlElement (getTagName()); - position.applyToXml (*e); - addColourAttributes (e); - e->setAttribute ("text", text); - e->setAttribute ("fontname", typefaceName); - e->setAttribute ("fontsize", roundToInt (font.getHeight() * 100.0) / 100.0); - e->setAttribute ("kerning", roundToInt (font.getExtraKerningFactor() * 1000.0) / 1000.0); - e->setAttribute ("bold", font.isBold()); - e->setAttribute ("italic", font.isItalic()); - e->setAttribute ("justification", justification.getFlags()); - if (font.getTypefaceStyle() != "Regular") - { - e->setAttribute ("typefaceStyle", font.getTypefaceStyle()); - } - - return e; - } - - bool loadFromXml (const XmlElement& xml) override - { - if (xml.hasTagName (getTagName())) - { - position.restoreFromXml (xml, position); - loadColourAttributes (xml); - - text = xml.getStringAttribute ("text", "Hello World"); - typefaceName = xml.getStringAttribute ("fontname", FontPropertyComponent::getDefaultFont()); - font = FontPropertyComponent::applyNameToFont (typefaceName, font); - font.setHeight ((float) xml.getDoubleAttribute ("fontsize", 15.0)); - font.setBold (xml.getBoolAttribute ("bold", false)); - font.setItalic (xml.getBoolAttribute ("italic", false)); - font.setExtraKerningFactor ((float) xml.getDoubleAttribute ("kerning", 0.0)); - justification = Justification (xml.getIntAttribute ("justification", Justification::centred)); - auto fontStyle = xml.getStringAttribute ("typefaceStyle"); - if (! fontStyle.isEmpty()) - font.setTypefaceStyle (fontStyle); - - return true; - } - - jassertfalse; - return false; - } - - //============================================================================== - const String& getText() const noexcept { return text; } - - class SetTextAction : public PaintElementUndoableAction - { - public: - SetTextAction (PaintElementText* const element, const String& newText_) - : PaintElementUndoableAction (element), - newText (newText_), - oldText (element->getText()) - { - } - - bool perform() - { - showCorrectTab(); - getElement()->setText (newText, false); - return true; - } - - bool undo() - { - showCorrectTab(); - getElement()->setText (oldText, false); - return true; - } - - private: - String newText, oldText; - }; - - void setText (const String& t, const bool undoable) - { - if (t != text) - { - if (undoable) - { - perform (new SetTextAction (this, t), - "Change text element text"); - } - else - { - text = t; - changed(); - } - } - } - - //============================================================================== - const Font& getFont() const { return font; } - - class SetFontAction : public PaintElementUndoableAction - { - public: - SetFontAction (PaintElementText* const element, const Font& newFont_) - : PaintElementUndoableAction (element), - newFont (newFont_), - oldFont (element->getFont()) - { - } - - bool perform() - { - showCorrectTab(); - getElement()->setFont (newFont, false); - return true; - } - - bool undo() - { - showCorrectTab(); - getElement()->setFont (oldFont, false); - return true; - } - - private: - Font newFont, oldFont; - }; - - void setFont (const Font& newFont, const bool undoable) - { - if (font != newFont) - { - if (undoable) - { - perform (new SetFontAction (this, newFont), - "Change text element font"); - } - else - { - font = newFont; - changed(); - } - } - } - - //============================================================================== - class SetTypefaceAction : public PaintElementUndoableAction - { - public: - SetTypefaceAction (PaintElementText* const element, const String& newValue_) - : PaintElementUndoableAction (element), - newValue (newValue_), - oldValue (element->getTypefaceName()) - { - } - - bool perform() - { - showCorrectTab(); - getElement()->setTypefaceName (newValue, false); - return true; - } - - bool undo() - { - showCorrectTab(); - getElement()->setTypefaceName (oldValue, false); - return true; - } - - private: - String newValue, oldValue; - }; - - void setTypefaceName (const String& newFontName, const bool undoable) - { - if (undoable) - { - perform (new SetTypefaceAction (this, newFontName), - "Change text element typeface"); - } - else - { - typefaceName = newFontName; - changed(); - } - } - - String getTypefaceName() const noexcept { return typefaceName; } - - //============================================================================== - Justification getJustification() const noexcept { return justification; } - - class SetJustifyAction : public PaintElementUndoableAction - { - public: - SetJustifyAction (PaintElementText* const element, Justification newValue_) - : PaintElementUndoableAction (element), - newValue (newValue_), - oldValue (element->getJustification()) - { - } - - bool perform() - { - showCorrectTab(); - getElement()->setJustification (newValue, false); - return true; - } - - bool undo() - { - showCorrectTab(); - getElement()->setJustification (oldValue, false); - return true; - } - - private: - Justification newValue, oldValue; - }; - - void setJustification (Justification j, const bool undoable) - { - if (justification.getFlags() != j.getFlags()) - { - if (undoable) - { - perform (new SetJustifyAction (this, j), - "Change text element justification"); - } - else - { - justification = j; - changed(); - } - } - } - - void convertToPath() - { - if (PaintRoutineEditor* parent = dynamic_cast (getParentComponent())) - { - - font = FontPropertyComponent::applyNameToFont (typefaceName, font); - - const Rectangle r = - getCurrentBounds (parent->getComponentArea().withZeroOrigin()); - - GlyphArrangement arr; - arr.addCurtailedLineOfText (font, text, - 0.0f, 0.0f, (float) r.getWidth(), - true); - - arr.justifyGlyphs (0, arr.getNumGlyphs(), - (float) r.getX(), (float) r.getY(), - (float) r.getWidth(), (float) r.getHeight(), - justification); - - Path path; - arr.createPath (path); - - convertToNewPathElement (path); - } - else - { - jassertfalse; - } - } - -private: - String text; - Font font; - String typefaceName; - Justification justification; - String customPaintCode; - - Array justificationTypes; - - //============================================================================== - class TextProperty : public TextPropertyComponent, - public ChangeListener - { - public: - TextProperty (PaintElementText* const e) - : TextPropertyComponent ("text", 2048, false), - element (e) - { - element->getDocument()->addChangeListener (this); - } - - ~TextProperty() override - { - element->getDocument()->removeChangeListener (this); - } - - void setText (const String& newText) override { element->setText (newText, true); } - String getText() const override { return element->getText(); } - - void changeListenerCallback (ChangeBroadcaster*) override { refresh(); } - - private: - PaintElementText* const element; - }; - - //============================================================================== - class FontNameProperty : public FontPropertyComponent, - public ChangeListener - { - public: - FontNameProperty (PaintElementText* const e) - : FontPropertyComponent ("font"), - element (e) - { - element->getDocument()->addChangeListener (this); - } - - ~FontNameProperty() - { - element->getDocument()->removeChangeListener (this); - } - - void setTypefaceName (const String& newFontName) { element->setTypefaceName (newFontName, true); } - String getTypefaceName() const { return element->getTypefaceName(); } - - void changeListenerCallback (ChangeBroadcaster*) { refresh(); } - - private: - PaintElementText* const element; - }; - - //============================================================================== - class FontStyleProperty : public ChoicePropertyComponent, - public ChangeListener - { - public: - FontStyleProperty (PaintElementText* const e) - : ChoicePropertyComponent ("style"), - element (e) - { - element->getDocument()->addChangeListener (this); - - updateStylesList (element->getTypefaceName()); - } - - ~FontStyleProperty() - { - element->getDocument()->removeChangeListener (this); - } - - void updateStylesList (const String& name) - { - if (getNumChildComponents() > 0) - { - if (auto cb = dynamic_cast (getChildComponent (0))) - cb->clear(); - - getChildComponent (0)->setVisible (false); - removeAllChildren(); - } - - choices.clear(); - - choices.add ("Regular"); - choices.add ("Bold"); - choices.add ("Italic"); - choices.add ("Bold Italic"); - - choices.mergeArray (Font::findAllTypefaceStyles (name)); - refresh(); - } - - void setIndex (int newIndex) - { - Font f (element->getFont()); - - if (f.getAvailableStyles().contains (choices[newIndex])) - { - f.setBold (false); - f.setItalic (false); - f.setTypefaceStyle (choices[newIndex]); - } - else - { - f.setTypefaceStyle ("Regular"); - f.setBold (newIndex == 1 || newIndex == 3); - f.setItalic (newIndex == 2 || newIndex == 3); - } - - element->setFont (f, true); - } - - int getIndex() const - { - auto f = element->getFont(); - - const auto typefaceIndex = choices.indexOf (f.getTypefaceStyle()); - if (typefaceIndex == -1) - { - if (f.isBold() && f.isItalic()) - return 3; - else if (f.isBold()) - return 1; - else if (f.isItalic()) - return 2; - - return 0; - } - - return typefaceIndex; - } - - void changeListenerCallback (ChangeBroadcaster*) - { - updateStylesList (element->getTypefaceName()); - } - - private: - PaintElementText* const element; - }; - - //============================================================================== - class FontSizeProperty : public SliderPropertyComponent, - public ChangeListener - { - public: - FontSizeProperty (PaintElementText* const e) - : SliderPropertyComponent ("size", 1.0, 250.0, 0.1, 0.3), - element (e) - { - element->getDocument()->addChangeListener (this); - } - - ~FontSizeProperty() - { - element->getDocument()->removeChangeListener (this); - } - - void setValue (double newValue) - { - element->getDocument()->getUndoManager().undoCurrentTransactionOnly(); - - Font f (element->getFont()); - f.setHeight ((float) newValue); - - element->setFont (f, true); - } - - double getValue() const - { - return element->getFont().getHeight(); - } - - void changeListenerCallback (ChangeBroadcaster*) { refresh(); } - - private: - PaintElementText* const element; - }; - - //============================================================================== - class FontKerningProperty : public SliderPropertyComponent, - public ChangeListener - { - public: - FontKerningProperty (PaintElementText* const e) - : SliderPropertyComponent ("kerning", -0.5, 0.5, 0.001), - element (e) - { - element->getDocument()->addChangeListener (this); - } - - ~FontKerningProperty() - { - element->getDocument()->removeChangeListener (this); - } - - void setValue (double newValue) - { - element->getDocument()->getUndoManager().undoCurrentTransactionOnly(); - - Font f (element->getFont()); - f.setExtraKerningFactor ((float) newValue); - - element->setFont (f, true); - } - - double getValue() const - { - return element->getFont().getExtraKerningFactor(); - } - - void changeListenerCallback (ChangeBroadcaster*) - { - refresh(); - } - - private: - PaintElementText* const element; - }; - - //============================================================================== - class TextJustificationProperty : public JustificationProperty, - public ChangeListener - { - public: - TextJustificationProperty (PaintElementText* const e) - : JustificationProperty ("layout", false), - element (e) - { - element->getDocument()->addChangeListener (this); - } - - ~TextJustificationProperty() - { - element->getDocument()->removeChangeListener (this); - } - - void setJustification (Justification newJustification) - { - element->setJustification (newJustification, true); - } - - Justification getJustification() const - { - return element->getJustification(); - } - - void changeListenerCallback (ChangeBroadcaster*) { refresh(); } - - private: - PaintElementText* const element; - }; - - //============================================================================== - class TextToPathProperty : public ButtonPropertyComponent - { - public: - TextToPathProperty (PaintElementText* const e) - : ButtonPropertyComponent ("path", false), - element (e) - { - } - - void buttonClicked() - { - element->convertToPath(); - } - - String getButtonText() const - { - return "convert text to a path"; - } - - private: - PaintElementText* const element; - }; -}; +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + By using JUCE, you agree to the terms of both the JUCE 5 End-User License + Agreement and JUCE 5 Privacy Policy (both updated and effective as of the + 22nd April 2020). + + End User License Agreement: www.juce.com/juce-5-licence + Privacy Policy: www.juce.com/juce-5-privacy-policy + + Or: You may also use this code under the terms of the GPL v3 (see + www.gnu.org/licenses). + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#pragma once + +#include "jucer_ColouredElement.h" +#include "../Properties/jucer_FontPropertyComponent.h" +#include "../Properties/jucer_JustificationProperty.h" + +//============================================================================== +class PaintElementText : public ColouredElement +{ +public: + PaintElementText (PaintRoutine* pr) + : ColouredElement (pr, "Text", false, false), + text ("Your text goes here"), + font (15.0f), + typefaceName (FontPropertyComponent::getDefaultFont()), + justification (Justification::centred) + { + fillType.colour = Colours::black; + position.rect.setWidth (200); + position.rect.setHeight (30); + } + + //============================================================================== + void draw (Graphics& g, const ComponentLayout* layout, const Rectangle& parentArea) override + { + fillType.setFillType (g, getDocument(), parentArea); + + font = FontPropertyComponent::applyNameToFont (typefaceName, font); + g.setFont (font); + + g.drawText (replaceStringTranslations (text, owner->getDocument()), + position.getRectangle (parentArea, layout), justification, true); + } + + static String replaceStringTranslations (String s, JucerDocument* document) + { + s = s.replace ("%%getName()%%", document->getComponentName()); + s = s.replace ("%%getButtonText()%%", document->getComponentName()); + return s; + } + + void getEditableProperties (Array& props, bool multipleSelected) override + { + ColouredElement::getEditableProperties (props, multipleSelected); + + if (multipleSelected) + return; + + props.add (new TextProperty (this)); + props.add (new FontNameProperty (this)); + props.add (new FontStyleProperty (this)); + props.add (new FontSizeProperty (this)); + props.add (new FontKerningProperty (this)); + props.add (new TextJustificationProperty (this)); + props.add (new TextToPathProperty (this)); + } + + void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) override + { + if (! fillType.isInvisible()) + { + String x, y, w, h, r; + positionToCode (position, code.document->getComponentLayout(), x, y, w, h); + r << "{\n" + << " int x = " << x << ", y = " << y << ", width = " << w << ", height = " << h << ";\n" + << " String text (" << quotedString (text, code.shouldUseTransMacro()) << ");\n" + << " " << fillType.generateVariablesCode ("fill") + << " //[UserPaintCustomArguments] Customize the painting arguments here..\n" + << customPaintCode + << " //[/UserPaintCustomArguments]\n" + << " "; + fillType.fillInGeneratedCode ("fill", position, code, r); + r << " g.setFont (" << FontPropertyComponent::getCompleteFontCode (font, typefaceName) << ");\n" + << " g.drawText (text, x, y, width, height,\n" + << " " << CodeHelpers::justificationToCode (justification) << ", true);\n" + << "}\n\n"; + + paintMethodCode += r; + } + } + + void applyCustomPaintSnippets (StringArray& snippets) override + { + customPaintCode.clear(); + + if (! snippets.isEmpty() && ! fillType.isInvisible()) + { + customPaintCode = snippets[0]; + snippets.remove (0); + } + } + + static const char* getTagName() noexcept { return "TEXT"; } + + XmlElement* createXml() const override + { + XmlElement* e = new XmlElement (getTagName()); + position.applyToXml (*e); + addColourAttributes (e); + e->setAttribute ("text", text); + e->setAttribute ("fontname", typefaceName); + e->setAttribute ("fontsize", roundToInt (font.getHeight() * 100.0) / 100.0); + e->setAttribute ("kerning", roundToInt (font.getExtraKerningFactor() * 1000.0) / 1000.0); + e->setAttribute ("bold", font.isBold()); + e->setAttribute ("italic", font.isItalic()); + e->setAttribute ("justification", justification.getFlags()); + if (font.getTypefaceStyle() != "Regular") + { + e->setAttribute ("typefaceStyle", font.getTypefaceStyle()); + } + + return e; + } + + bool loadFromXml (const XmlElement& xml) override + { + if (xml.hasTagName (getTagName())) + { + position.restoreFromXml (xml, position); + loadColourAttributes (xml); + + text = xml.getStringAttribute ("text", "Hello World"); + typefaceName = xml.getStringAttribute ("fontname", FontPropertyComponent::getDefaultFont()); + font = FontPropertyComponent::applyNameToFont (typefaceName, font); + font.setHeight ((float) xml.getDoubleAttribute ("fontsize", 15.0)); + font.setBold (xml.getBoolAttribute ("bold", false)); + font.setItalic (xml.getBoolAttribute ("italic", false)); + font.setExtraKerningFactor ((float) xml.getDoubleAttribute ("kerning", 0.0)); + justification = Justification (xml.getIntAttribute ("justification", Justification::centred)); + auto fontStyle = xml.getStringAttribute ("typefaceStyle"); + if (! fontStyle.isEmpty()) + font.setTypefaceStyle (fontStyle); + + return true; + } + + jassertfalse; + return false; + } + + //============================================================================== + const String& getText() const noexcept { return text; } + + class SetTextAction : public PaintElementUndoableAction + { + public: + SetTextAction (PaintElementText* const element, const String& newText_) + : PaintElementUndoableAction (element), + newText (newText_), + oldText (element->getText()) + { + } + + bool perform() + { + showCorrectTab(); + getElement()->setText (newText, false); + return true; + } + + bool undo() + { + showCorrectTab(); + getElement()->setText (oldText, false); + return true; + } + + private: + String newText, oldText; + }; + + void setText (const String& t, const bool undoable) + { + if (t != text) + { + if (undoable) + { + perform (new SetTextAction (this, t), + "Change text element text"); + } + else + { + text = t; + changed(); + } + } + } + + //============================================================================== + const Font& getFont() const { return font; } + + class SetFontAction : public PaintElementUndoableAction + { + public: + SetFontAction (PaintElementText* const element, const Font& newFont_) + : PaintElementUndoableAction (element), + newFont (newFont_), + oldFont (element->getFont()) + { + } + + bool perform() + { + showCorrectTab(); + getElement()->setFont (newFont, false); + return true; + } + + bool undo() + { + showCorrectTab(); + getElement()->setFont (oldFont, false); + return true; + } + + private: + Font newFont, oldFont; + }; + + void setFont (const Font& newFont, const bool undoable) + { + if (font != newFont) + { + if (undoable) + { + perform (new SetFontAction (this, newFont), + "Change text element font"); + } + else + { + font = newFont; + changed(); + } + } + } + + //============================================================================== + class SetTypefaceAction : public PaintElementUndoableAction + { + public: + SetTypefaceAction (PaintElementText* const element, const String& newValue_) + : PaintElementUndoableAction (element), + newValue (newValue_), + oldValue (element->getTypefaceName()) + { + } + + bool perform() + { + showCorrectTab(); + getElement()->setTypefaceName (newValue, false); + return true; + } + + bool undo() + { + showCorrectTab(); + getElement()->setTypefaceName (oldValue, false); + return true; + } + + private: + String newValue, oldValue; + }; + + void setTypefaceName (const String& newFontName, const bool undoable) + { + if (undoable) + { + perform (new SetTypefaceAction (this, newFontName), + "Change text element typeface"); + } + else + { + typefaceName = newFontName; + changed(); + } + } + + String getTypefaceName() const noexcept { return typefaceName; } + + //============================================================================== + Justification getJustification() const noexcept { return justification; } + + class SetJustifyAction : public PaintElementUndoableAction + { + public: + SetJustifyAction (PaintElementText* const element, Justification newValue_) + : PaintElementUndoableAction (element), + newValue (newValue_), + oldValue (element->getJustification()) + { + } + + bool perform() + { + showCorrectTab(); + getElement()->setJustification (newValue, false); + return true; + } + + bool undo() + { + showCorrectTab(); + getElement()->setJustification (oldValue, false); + return true; + } + + private: + Justification newValue, oldValue; + }; + + void setJustification (Justification j, const bool undoable) + { + if (justification.getFlags() != j.getFlags()) + { + if (undoable) + { + perform (new SetJustifyAction (this, j), + "Change text element justification"); + } + else + { + justification = j; + changed(); + } + } + } + + void convertToPath() + { + if (PaintRoutineEditor* parent = dynamic_cast (getParentComponent())) + { + + font = FontPropertyComponent::applyNameToFont (typefaceName, font); + + const Rectangle r = + getCurrentBounds (parent->getComponentArea().withZeroOrigin()); + + GlyphArrangement arr; + arr.addCurtailedLineOfText (font, text, + 0.0f, 0.0f, (float) r.getWidth(), + true); + + arr.justifyGlyphs (0, arr.getNumGlyphs(), + (float) r.getX(), (float) r.getY(), + (float) r.getWidth(), (float) r.getHeight(), + justification); + + Path path; + arr.createPath (path); + + convertToNewPathElement (path); + } + else + { + jassertfalse; + } + } + +private: + String text; + Font font; + String typefaceName; + Justification justification; + String customPaintCode; + + Array justificationTypes; + + //============================================================================== + class TextProperty : public TextPropertyComponent, + public ChangeListener + { + public: + TextProperty (PaintElementText* const e) + : TextPropertyComponent ("text", 2048, false), + element (e) + { + element->getDocument()->addChangeListener (this); + } + + ~TextProperty() override + { + element->getDocument()->removeChangeListener (this); + } + + void setText (const String& newText) override { element->setText (newText, true); } + String getText() const override { return element->getText(); } + + void changeListenerCallback (ChangeBroadcaster*) override { refresh(); } + + private: + PaintElementText* const element; + }; + + //============================================================================== + class FontNameProperty : public FontPropertyComponent, + public ChangeListener + { + public: + FontNameProperty (PaintElementText* const e) + : FontPropertyComponent ("font"), + element (e) + { + element->getDocument()->addChangeListener (this); + } + + ~FontNameProperty() + { + element->getDocument()->removeChangeListener (this); + } + + void setTypefaceName (const String& newFontName) { element->setTypefaceName (newFontName, true); } + String getTypefaceName() const { return element->getTypefaceName(); } + + void changeListenerCallback (ChangeBroadcaster*) { refresh(); } + + private: + PaintElementText* const element; + }; + + //============================================================================== + class FontStyleProperty : public ChoicePropertyComponent, + public ChangeListener + { + public: + FontStyleProperty (PaintElementText* const e) + : ChoicePropertyComponent ("style"), + element (e) + { + element->getDocument()->addChangeListener (this); + + updateStylesList (element->getTypefaceName()); + } + + ~FontStyleProperty() + { + element->getDocument()->removeChangeListener (this); + } + + void updateStylesList (const String& name) + { + if (getNumChildComponents() > 0) + { + if (auto cb = dynamic_cast (getChildComponent (0))) + cb->clear(); + + getChildComponent (0)->setVisible (false); + removeAllChildren(); + } + + choices.clear(); + + choices.add ("Regular"); + choices.add ("Bold"); + choices.add ("Italic"); + choices.add ("Bold Italic"); + + choices.mergeArray (Font::findAllTypefaceStyles (name)); + refresh(); + } + + void setIndex (int newIndex) + { + Font f (element->getFont()); + + if (f.getAvailableStyles().contains (choices[newIndex])) + { + f.setBold (false); + f.setItalic (false); + f.setTypefaceStyle (choices[newIndex]); + } + else + { + f.setTypefaceStyle ("Regular"); + f.setBold (newIndex == 1 || newIndex == 3); + f.setItalic (newIndex == 2 || newIndex == 3); + } + + element->setFont (f, true); + } + + int getIndex() const + { + auto f = element->getFont(); + + const auto typefaceIndex = choices.indexOf (f.getTypefaceStyle()); + if (typefaceIndex == -1) + { + if (f.isBold() && f.isItalic()) + return 3; + else if (f.isBold()) + return 1; + else if (f.isItalic()) + return 2; + + return 0; + } + + return typefaceIndex; + } + + void changeListenerCallback (ChangeBroadcaster*) + { + updateStylesList (element->getTypefaceName()); + } + + private: + PaintElementText* const element; + }; + + //============================================================================== + class FontSizeProperty : public SliderPropertyComponent, + public ChangeListener + { + public: + FontSizeProperty (PaintElementText* const e) + : SliderPropertyComponent ("size", 1.0, 250.0, 0.1, 0.3), + element (e) + { + element->getDocument()->addChangeListener (this); + } + + ~FontSizeProperty() + { + element->getDocument()->removeChangeListener (this); + } + + void setValue (double newValue) + { + element->getDocument()->getUndoManager().undoCurrentTransactionOnly(); + + Font f (element->getFont()); + f.setHeight ((float) newValue); + + element->setFont (f, true); + } + + double getValue() const + { + return element->getFont().getHeight(); + } + + void changeListenerCallback (ChangeBroadcaster*) { refresh(); } + + private: + PaintElementText* const element; + }; + + //============================================================================== + class FontKerningProperty : public SliderPropertyComponent, + public ChangeListener + { + public: + FontKerningProperty (PaintElementText* const e) + : SliderPropertyComponent ("kerning", -0.5, 0.5, 0.001), + element (e) + { + element->getDocument()->addChangeListener (this); + } + + ~FontKerningProperty() + { + element->getDocument()->removeChangeListener (this); + } + + void setValue (double newValue) + { + element->getDocument()->getUndoManager().undoCurrentTransactionOnly(); + + Font f (element->getFont()); + f.setExtraKerningFactor ((float) newValue); + + element->setFont (f, true); + } + + double getValue() const + { + return element->getFont().getExtraKerningFactor(); + } + + void changeListenerCallback (ChangeBroadcaster*) + { + refresh(); + } + + private: + PaintElementText* const element; + }; + + //============================================================================== + class TextJustificationProperty : public JustificationProperty, + public ChangeListener + { + public: + TextJustificationProperty (PaintElementText* const e) + : JustificationProperty ("layout", false), + element (e) + { + element->getDocument()->addChangeListener (this); + } + + ~TextJustificationProperty() + { + element->getDocument()->removeChangeListener (this); + } + + void setJustification (Justification newJustification) + { + element->setJustification (newJustification, true); + } + + Justification getJustification() const + { + return element->getJustification(); + } + + void changeListenerCallback (ChangeBroadcaster*) { refresh(); } + + private: + PaintElementText* const element; + }; + + //============================================================================== + class TextToPathProperty : public ButtonPropertyComponent + { + public: + TextToPathProperty (PaintElementText* const e) + : ButtonPropertyComponent ("path", false), + element (e) + { + } + + void buttonClicked() + { + element->convertToPath(); + } + + String getButtonText() const + { + return "convert text to a path"; + } + + private: + PaintElementText* const element; + }; +}; diff --git a/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.cpp b/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.cpp index 2aeb2cb2f4..96841cdd26 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.cpp +++ b/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.cpp @@ -1,349 +1,349 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2020 - Raw Material Software Limited - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 22nd April 2020). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -#include "../Application/jucer_Headers.h" -#include "jucer_GeneratedCode.h" -#include "jucer_JucerDocument.h" - -//============================================================================== -GeneratedCode::GeneratedCode (const JucerDocument* const doc) - : document (doc), suffix (0) -{ -} - -GeneratedCode::~GeneratedCode() -{ -} - -int GeneratedCode::getUniqueSuffix() -{ - return ++suffix; -} - -//============================================================================== -String& GeneratedCode::getCallbackCode (const String& requiredParentClass, - const String& returnType, - const String& prototype, - const bool hasPrePostUserSections) -{ - String parentClass (requiredParentClass); - if (parentClass.isNotEmpty() - && ! (parentClass.startsWith ("public ") - || parentClass.startsWith ("private ") - || parentClass.startsWith ("protected "))) - { - parentClass = "public " + parentClass; - } - - for (int i = callbacks.size(); --i >= 0;) - { - CallbackMethod* const cm = callbacks.getUnchecked(i); - - if (cm->requiredParentClass == parentClass - && cm->returnType == returnType - && cm->prototype == prototype) - return cm->content; - } - - CallbackMethod* const cm = new CallbackMethod(); - callbacks.add (cm); - - cm->requiredParentClass = parentClass; - cm->returnType = returnType; - cm->prototype = prototype; - cm->hasPrePostUserSections = hasPrePostUserSections; - return cm->content; -} - -void GeneratedCode::removeCallback (const String& returnType, const String& prototype) -{ - for (int i = callbacks.size(); --i >= 0;) - { - CallbackMethod* const cm = callbacks.getUnchecked(i); - - if (cm->returnType == returnType && cm->prototype == prototype) - callbacks.remove (i); - } -} - -void GeneratedCode::addImageResourceLoader (const String& imageMemberName, const String& resourceName) -{ - privateMemberDeclarations - << "Image " << imageMemberName << ";\n"; - - if (resourceName.isNotEmpty()) - constructorCode << imageMemberName << " = ImageCache::getFromMemory (" - << resourceName << ", " << resourceName << "Size);\n"; -} - -StringArray GeneratedCode::getExtraParentClasses() const -{ - StringArray s; - - for (int i = 0; i < callbacks.size(); ++i) - { - CallbackMethod* const cm = callbacks.getUnchecked(i); - s.add (cm->requiredParentClass); - } - - return s; -} - -String GeneratedCode::getCallbackDeclarations() const -{ - String s; - - for (int i = 0; i < callbacks.size(); ++i) - { - CallbackMethod* const cm = callbacks.getUnchecked(i); - - s << cm->returnType << " " << cm->prototype << " override;\n"; - } - - return s; -} - -String GeneratedCode::getCallbackDefinitions() const -{ - String s; - - for (int i = 0; i < callbacks.size(); ++i) - { - CallbackMethod* const cm = callbacks.getUnchecked(i); - - const String userCodeBlockName ("User" - + CodeHelpers::makeValidIdentifier (cm->prototype.upToFirstOccurrenceOf ("(", false, false), - true, true, false).trim()); - - if (userCodeBlockName.isNotEmpty() && cm->hasPrePostUserSections) - { - s << cm->returnType << " " << className << "::" << cm->prototype - << "\n{\n //[" << userCodeBlockName << "_Pre]\n //[/" << userCodeBlockName - << "_Pre]\n\n " - << CodeHelpers::indent (cm->content.trim(), 4, false) - << "\n\n //[" << userCodeBlockName << "_Post]\n //[/" << userCodeBlockName - << "_Post]\n}\n\n"; - } - else - { - s << cm->returnType << " " << className << "::" << cm->prototype - << "\n{\n " - << CodeHelpers::indent (cm->content.trim(), 4, false) - << "\n}\n\n"; - } - } - - return s; -} - -//============================================================================== -String GeneratedCode::getClassDeclaration() const -{ - StringArray parentClassLines; - parentClassLines.addTokens (parentClasses, ",", StringRef()); - parentClassLines.addArray (getExtraParentClasses()); - - parentClassLines = getCleanedStringArray (parentClassLines); - - if (parentClassLines.contains ("public Button", false)) - parentClassLines.removeString ("public Component", false); - - String r ("class "); - r << className << " : "; - - r += parentClassLines.joinIntoString (",\n" + String::repeatedString (" ", r.length())); - - return r; -} - -String GeneratedCode::getInitialiserList() const -{ - StringArray inits (initialisers); - - if (parentClassInitialiser.isNotEmpty()) - inits.insert (0, parentClassInitialiser); - - inits = getCleanedStringArray (inits); - - String s; - - if (inits.size() == 0) - return s; - - s << " : "; - - for (int i = 0; i < inits.size(); ++i) - { - String init (inits[i]); - - while (init.endsWithChar (',')) - init = init.dropLastCharacters (1); - - s << init; - - if (i < inits.size() - 1) - s << ",\n "; - else - s << "\n"; - } - - return s; -} - -static String getIncludeFileCode (const Array& files, const File& targetFile) -{ - String s; - - for (int i = 0; i < files.size(); ++i) - s << CodeHelpers::createIncludeStatement (files.getReference(i), targetFile) << newLine; - - return s; -} - -bool GeneratedCode::shouldUseTransMacro() const noexcept -{ - return document->shouldUseTransMacro(); -} - -//============================================================================== -static void replaceTemplate (String& text, const String& itemName, const String& value) -{ - for (;;) - { - const int index = text.indexOf ("%%" + itemName + "%%"); - - if (index < 0) - break; - - int indentLevel = 0; - - for (int i = index; --i >= 0;) - { - if (text[i] == '\n') - break; - - ++indentLevel; - } - - text = text.replaceSection (index, itemName.length() + 4, - CodeHelpers::indent (value, indentLevel, false)); - } -} - -//============================================================================== -static bool getUserSection (const StringArray& lines, const String& tag, StringArray& resultLines) -{ - const int start = indexOfLineStartingWith (lines, "//[" + tag + "]", 0); - - if (start < 0) - return false; - - const int end = indexOfLineStartingWith (lines, "//[/" + tag + "]", start + 1); - - for (int i = start + 1; i < end; ++i) - resultLines.add (lines [i]); - - return true; -} - -static void copyAcrossUserSections (String& dest, const String& src) -{ - StringArray srcLines, dstLines; - srcLines.addLines (src); - dstLines.addLines (dest); - - for (int i = 0; i < dstLines.size(); ++i) - { - if (dstLines[i].trimStart().startsWith ("//[")) - { - String tag (dstLines[i].trimStart().substring (3)); - tag = tag.upToFirstOccurrenceOf ("]", false, false); - - jassert (! tag.startsWithChar ('/')); - - if (! tag.startsWithChar ('/')) - { - const int endLine = indexOfLineStartingWith (dstLines, - "//[/" + tag + "]", - i + 1); - - if (endLine > i) - { - StringArray sourceLines; - - if (tag != "UserPaintCustomArguments" && getUserSection (srcLines, tag, sourceLines)) - { - for (int j = endLine - i; --j > 0;) - dstLines.remove (i + 1); - - for (int j = 0; j < sourceLines.size(); ++j) - dstLines.insert (++i, sourceLines [j].trimEnd()); - - ++i; - } - else - { - i = endLine; - } - } - } - } - - dstLines.set (i, dstLines[i].trimEnd()); - } - - dest = dstLines.joinIntoString ("\n") + "\n"; -} - -//============================================================================== -void GeneratedCode::applyToCode (String& code, const File& targetFile, const String& oldFileWithUserData) const -{ - replaceTemplate (code, "version", JUCEApplicationBase::getInstance()->getApplicationVersion()); - replaceTemplate (code, "creationTime", Time::getCurrentTime().toString (true, true, true)); - - replaceTemplate (code, "class_name", className); - replaceTemplate (code, "constructor_params", constructorParams); - replaceTemplate (code, "initialisers", getInitialiserList()); - - replaceTemplate (code, "class_declaration", getClassDeclaration()); - replaceTemplate (code, "private_member_declarations", privateMemberDeclarations); - replaceTemplate (code, "public_member_declarations", getCallbackDeclarations() + newLine + publicMemberDeclarations); - - replaceTemplate (code, "method_definitions", getCallbackDefinitions()); - - replaceTemplate (code, "include_juce", CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename())); - - replaceTemplate (code, "include_files_h", getIncludeFileCode (includeFilesH, targetFile)); - replaceTemplate (code, "include_files_cpp", getIncludeFileCode (includeFilesCPP, targetFile)); - - replaceTemplate (code, "constructor", constructorCode); - replaceTemplate (code, "destructor", destructorCode); - - replaceTemplate (code, "metadata", jucerMetadata); - replaceTemplate (code, "static_member_definitions", staticMemberDefinitions); - - copyAcrossUserSections (code, oldFileWithUserData); -} +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + By using JUCE, you agree to the terms of both the JUCE 5 End-User License + Agreement and JUCE 5 Privacy Policy (both updated and effective as of the + 22nd April 2020). + + End User License Agreement: www.juce.com/juce-5-licence + Privacy Policy: www.juce.com/juce-5-privacy-policy + + Or: You may also use this code under the terms of the GPL v3 (see + www.gnu.org/licenses). + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "../Application/jucer_Headers.h" +#include "jucer_GeneratedCode.h" +#include "jucer_JucerDocument.h" + +//============================================================================== +GeneratedCode::GeneratedCode (const JucerDocument* const doc) + : document (doc), suffix (0) +{ +} + +GeneratedCode::~GeneratedCode() +{ +} + +int GeneratedCode::getUniqueSuffix() +{ + return ++suffix; +} + +//============================================================================== +String& GeneratedCode::getCallbackCode (const String& requiredParentClass, + const String& returnType, + const String& prototype, + const bool hasPrePostUserSections) +{ + String parentClass (requiredParentClass); + if (parentClass.isNotEmpty() + && ! (parentClass.startsWith ("public ") + || parentClass.startsWith ("private ") + || parentClass.startsWith ("protected "))) + { + parentClass = "public " + parentClass; + } + + for (int i = callbacks.size(); --i >= 0;) + { + CallbackMethod* const cm = callbacks.getUnchecked(i); + + if (cm->requiredParentClass == parentClass + && cm->returnType == returnType + && cm->prototype == prototype) + return cm->content; + } + + CallbackMethod* const cm = new CallbackMethod(); + callbacks.add (cm); + + cm->requiredParentClass = parentClass; + cm->returnType = returnType; + cm->prototype = prototype; + cm->hasPrePostUserSections = hasPrePostUserSections; + return cm->content; +} + +void GeneratedCode::removeCallback (const String& returnType, const String& prototype) +{ + for (int i = callbacks.size(); --i >= 0;) + { + CallbackMethod* const cm = callbacks.getUnchecked(i); + + if (cm->returnType == returnType && cm->prototype == prototype) + callbacks.remove (i); + } +} + +void GeneratedCode::addImageResourceLoader (const String& imageMemberName, const String& resourceName) +{ + privateMemberDeclarations + << "Image " << imageMemberName << ";\n"; + + if (resourceName.isNotEmpty()) + constructorCode << imageMemberName << " = ImageCache::getFromMemory (" + << resourceName << ", " << resourceName << "Size);\n"; +} + +StringArray GeneratedCode::getExtraParentClasses() const +{ + StringArray s; + + for (int i = 0; i < callbacks.size(); ++i) + { + CallbackMethod* const cm = callbacks.getUnchecked(i); + s.add (cm->requiredParentClass); + } + + return s; +} + +String GeneratedCode::getCallbackDeclarations() const +{ + String s; + + for (int i = 0; i < callbacks.size(); ++i) + { + CallbackMethod* const cm = callbacks.getUnchecked(i); + + s << cm->returnType << " " << cm->prototype << " override;\n"; + } + + return s; +} + +String GeneratedCode::getCallbackDefinitions() const +{ + String s; + + for (int i = 0; i < callbacks.size(); ++i) + { + CallbackMethod* const cm = callbacks.getUnchecked(i); + + const String userCodeBlockName ("User" + + CodeHelpers::makeValidIdentifier (cm->prototype.upToFirstOccurrenceOf ("(", false, false), + true, true, false).trim()); + + if (userCodeBlockName.isNotEmpty() && cm->hasPrePostUserSections) + { + s << cm->returnType << " " << className << "::" << cm->prototype + << "\n{\n //[" << userCodeBlockName << "_Pre]\n //[/" << userCodeBlockName + << "_Pre]\n\n " + << CodeHelpers::indent (cm->content.trim(), 4, false) + << "\n\n //[" << userCodeBlockName << "_Post]\n //[/" << userCodeBlockName + << "_Post]\n}\n\n"; + } + else + { + s << cm->returnType << " " << className << "::" << cm->prototype + << "\n{\n " + << CodeHelpers::indent (cm->content.trim(), 4, false) + << "\n}\n\n"; + } + } + + return s; +} + +//============================================================================== +String GeneratedCode::getClassDeclaration() const +{ + StringArray parentClassLines; + parentClassLines.addTokens (parentClasses, ",", StringRef()); + parentClassLines.addArray (getExtraParentClasses()); + + parentClassLines = getCleanedStringArray (parentClassLines); + + if (parentClassLines.contains ("public Button", false)) + parentClassLines.removeString ("public Component", false); + + String r ("class "); + r << className << " : "; + + r += parentClassLines.joinIntoString (",\n" + String::repeatedString (" ", r.length())); + + return r; +} + +String GeneratedCode::getInitialiserList() const +{ + StringArray inits (initialisers); + + if (parentClassInitialiser.isNotEmpty()) + inits.insert (0, parentClassInitialiser); + + inits = getCleanedStringArray (inits); + + String s; + + if (inits.size() == 0) + return s; + + s << " : "; + + for (int i = 0; i < inits.size(); ++i) + { + String init (inits[i]); + + while (init.endsWithChar (',')) + init = init.dropLastCharacters (1); + + s << init; + + if (i < inits.size() - 1) + s << ",\n "; + else + s << "\n"; + } + + return s; +} + +static String getIncludeFileCode (const Array& files, const File& targetFile) +{ + String s; + + for (int i = 0; i < files.size(); ++i) + s << CodeHelpers::createIncludeStatement (files.getReference(i), targetFile) << newLine; + + return s; +} + +bool GeneratedCode::shouldUseTransMacro() const noexcept +{ + return document->shouldUseTransMacro(); +} + +//============================================================================== +static void replaceTemplate (String& text, const String& itemName, const String& value) +{ + for (;;) + { + const int index = text.indexOf ("%%" + itemName + "%%"); + + if (index < 0) + break; + + int indentLevel = 0; + + for (int i = index; --i >= 0;) + { + if (text[i] == '\n') + break; + + ++indentLevel; + } + + text = text.replaceSection (index, itemName.length() + 4, + CodeHelpers::indent (value, indentLevel, false)); + } +} + +//============================================================================== +static bool getUserSection (const StringArray& lines, const String& tag, StringArray& resultLines) +{ + const int start = indexOfLineStartingWith (lines, "//[" + tag + "]", 0); + + if (start < 0) + return false; + + const int end = indexOfLineStartingWith (lines, "//[/" + tag + "]", start + 1); + + for (int i = start + 1; i < end; ++i) + resultLines.add (lines [i]); + + return true; +} + +static void copyAcrossUserSections (String& dest, const String& src) +{ + StringArray srcLines, dstLines; + srcLines.addLines (src); + dstLines.addLines (dest); + + for (int i = 0; i < dstLines.size(); ++i) + { + if (dstLines[i].trimStart().startsWith ("//[")) + { + String tag (dstLines[i].trimStart().substring (3)); + tag = tag.upToFirstOccurrenceOf ("]", false, false); + + jassert (! tag.startsWithChar ('/')); + + if (! tag.startsWithChar ('/')) + { + const int endLine = indexOfLineStartingWith (dstLines, + "//[/" + tag + "]", + i + 1); + + if (endLine > i) + { + StringArray sourceLines; + + if (tag != "UserPaintCustomArguments" && getUserSection (srcLines, tag, sourceLines)) + { + for (int j = endLine - i; --j > 0;) + dstLines.remove (i + 1); + + for (int j = 0; j < sourceLines.size(); ++j) + dstLines.insert (++i, sourceLines [j].trimEnd()); + + ++i; + } + else + { + i = endLine; + } + } + } + } + + dstLines.set (i, dstLines[i].trimEnd()); + } + + dest = dstLines.joinIntoString ("\n") + "\n"; +} + +//============================================================================== +void GeneratedCode::applyToCode (String& code, const File& targetFile, const String& oldFileWithUserData) const +{ + replaceTemplate (code, "version", JUCEApplicationBase::getInstance()->getApplicationVersion()); + replaceTemplate (code, "creationTime", Time::getCurrentTime().toString (true, true, true)); + + replaceTemplate (code, "class_name", className); + replaceTemplate (code, "constructor_params", constructorParams); + replaceTemplate (code, "initialisers", getInitialiserList()); + + replaceTemplate (code, "class_declaration", getClassDeclaration()); + replaceTemplate (code, "private_member_declarations", privateMemberDeclarations); + replaceTemplate (code, "public_member_declarations", getCallbackDeclarations() + newLine + publicMemberDeclarations); + + replaceTemplate (code, "method_definitions", getCallbackDefinitions()); + + replaceTemplate (code, "include_juce", CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename())); + + replaceTemplate (code, "include_files_h", getIncludeFileCode (includeFilesH, targetFile)); + replaceTemplate (code, "include_files_cpp", getIncludeFileCode (includeFilesCPP, targetFile)); + + replaceTemplate (code, "constructor", constructorCode); + replaceTemplate (code, "destructor", destructorCode); + + replaceTemplate (code, "metadata", jucerMetadata); + replaceTemplate (code, "static_member_definitions", staticMemberDefinitions); + + copyAcrossUserSections (code, oldFileWithUserData); +}