diff --git a/extras/Projucer/Source/ComponentEditor/documents/jucer_ComponentDocument.cpp b/extras/Projucer/Source/ComponentEditor/documents/jucer_ComponentDocument.cpp index be6aeb489b..47637c718a 100644 --- a/extras/Projucer/Source/ComponentEditor/documents/jucer_ComponentDocument.cpp +++ b/extras/Projucer/Source/ComponentEditor/documents/jucer_ComponentDocument.cpp @@ -93,6 +93,11 @@ bool ComponentDocument::loadFromXml (const XmlElement& xml) return false; } +void ComponentDocument::applyCustomPaintSnippets (StringArray& snippets) +{ + backgroundGraphics->applyCustomPaintSnippets (snippets); +} + //============================================================================== class NormalTestComponent : public Component { diff --git a/extras/Projucer/Source/ComponentEditor/documents/jucer_ComponentDocument.h b/extras/Projucer/Source/ComponentEditor/documents/jucer_ComponentDocument.h index 8a4a9752a9..f7a74665d1 100644 --- a/extras/Projucer/Source/ComponentEditor/documents/jucer_ComponentDocument.h +++ b/extras/Projucer/Source/ComponentEditor/documents/jucer_ComponentDocument.h @@ -53,6 +53,7 @@ public: bool loadFromXml (const XmlElement& xml); void fillInGeneratedCode (GeneratedCode& code) const; + void applyCustomPaintSnippets (StringArray&); private: ScopedPointer components; diff --git a/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.cpp b/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.cpp index 8957b9e0cb..be3a9788ee 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.cpp +++ b/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.cpp @@ -294,7 +294,7 @@ static void copyAcrossUserSections (String& dest, const String& src) { StringArray sourceLines; - if (getUserSection (srcLines, tag, sourceLines)) + if (tag != "UserPaintCustomArguments" && getUserSection (srcLines, tag, sourceLines)) { for (int j = endLine - i; --j > 0;) dstLines.remove (i + 1); diff --git a/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp b/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp index e2f24379db..261691d608 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp +++ b/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp @@ -42,14 +42,7 @@ const char* const defaultParentClasses = "public Component"; JucerDocument::JucerDocument (SourceCodeDocument* c) : cpp (c), className (defaultClassName), - parentClasses (defaultParentClasses), - fixedSize (false), - initialWidth (600), - initialHeight (400), - snapGridPixels (8), - snapActive (true), - snapShown (true), - componentOverlayOpacity (0.33f) + parentClasses (defaultParentClasses) { jassert (cpp != nullptr); resources.setDocument (this); @@ -599,13 +592,49 @@ bool JucerDocument::reloadFromDocument() resources.loadFromCpp (getCppFile(), cppContent); - return loadFromXml (*currentXML); + bool result = loadFromXml (*currentXML); + extractCustomPaintSnippetsFromCppFile (cppContent); + return result; +} + +void JucerDocument::refreshCustomCodeFromDocument() +{ + const String cppContent (cpp->getCodeDocument().getAllContent()); + extractCustomPaintSnippetsFromCppFile (cppContent); +} + +void JucerDocument::extractCustomPaintSnippetsFromCppFile (const String& cppContent) +{ + StringArray customPaintSnippets; + + auto lines = StringArray::fromLines (cppContent); + int last = 0; + + while (last >= 0) + { + const int start = indexOfLineStartingWith (lines, "//[UserPaintCustomArguments]", last); + if (start < 0) + break; + + const int end = indexOfLineStartingWith (lines, "//[/UserPaintCustomArguments]", start); + if (end < 0) + break; + + last = end + 1; + String result; + + for (int i = start + 1; i < end; ++i) + result << lines [i] << newLine; + + customPaintSnippets.add (CodeHelpers::unindent (result, 4)); + } + + applyCustomPaintSnippets (customPaintSnippets); } XmlElement* JucerDocument::pullMetaDataFromCppFile (const String& cpp) { - StringArray lines; - lines.addLines (cpp); + auto lines = StringArray::fromLines (cpp); const int startLine = indexOfLineStartingWith (lines, "BEGIN_JUCER_METADATA", 0); @@ -624,17 +653,15 @@ XmlElement* JucerDocument::pullMetaDataFromCppFile (const String& cpp) bool JucerDocument::isValidJucerCppFile (const File& f) { if (f.hasFileExtension (".cpp")) - { - const ScopedPointer xml (pullMetaDataFromCppFile (f.loadFileAsString())); - return xml != nullptr && xml->hasTagName (jucerCompXmlTag); - } + if (ScopedPointer xml = pullMetaDataFromCppFile (f.loadFileAsString())) + return xml->hasTagName (jucerCompXmlTag); return false; } static JucerDocument* createDocument (SourceCodeDocument* cpp) { - CodeDocument& codeDoc = cpp->getCodeDocument(); + auto& codeDoc = cpp->getCodeDocument(); ScopedPointer xml (JucerDocument::pullMetaDataFromCppFile (codeDoc.getAllContent())); @@ -684,9 +711,9 @@ public: bool saveHeader() { - OpenDocumentManager& odm = ProjucerApplication::getApp().openDocumentManager; + auto& odm = ProjucerApplication::getApp().openDocumentManager; - if (OpenDocumentManager::Document* header = odm.openFile (nullptr, getFile().withFileExtension (".h"))) + if (auto* header = odm.openFile (nullptr, getFile().withFileExtension (".h"))) return header->save(); return false; @@ -694,9 +721,7 @@ public: Component* createEditor() override { - ScopedPointer jucerDoc (JucerDocument::createForCppFile (getProject(), getFile())); - - if (jucerDoc != nullptr) + if (ScopedPointer jucerDoc = JucerDocument::createForCppFile (getProject(), getFile())) return new JucerDocumentEditor (jucerDoc.release()); return SourceCodeDocument::createEditor(); @@ -736,15 +761,13 @@ public: headerFile.replaceWithText (String()); cppFile.replaceWithText (String()); - OpenDocumentManager& odm = ProjucerApplication::getApp().openDocumentManager; + auto& odm = ProjucerApplication::getApp().openDocumentManager; - if (SourceCodeDocument* cpp = dynamic_cast (odm.openFile (nullptr, cppFile))) + if (auto* cpp = dynamic_cast (odm.openFile (nullptr, cppFile))) { - if (SourceCodeDocument* header = dynamic_cast (odm.openFile (nullptr, headerFile))) + if (auto* header = dynamic_cast (odm.openFile (nullptr, headerFile))) { - ScopedPointer jucerDoc (new ComponentDocument (cpp)); - - if (jucerDoc != nullptr) + if (ScopedPointer jucerDoc = new ComponentDocument (cpp)) { jucerDoc->setClassName (newFile.getFileNameWithoutExtension()); diff --git a/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.h b/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.h index c112911bf8..f69269adc9 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.h +++ b/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.h @@ -136,14 +136,17 @@ public: static bool shouldUseTransMacro() noexcept { return true; } + //============================================================================== + void refreshCustomCodeFromDocument(); + protected: SourceCodeDocument* cpp; String className, componentName, templateFile; String parentClasses, constructorParams, variableInitialisers; - bool fixedSize; - int initialWidth, initialHeight; + bool fixedSize = false; + int initialWidth = 600, initialHeight = 400; BinaryResources resources; @@ -153,6 +156,8 @@ protected: virtual void fillInGeneratedCode (GeneratedCode&) const; virtual void fillInPaintCode (GeneratedCode&) const; + virtual void applyCustomPaintSnippets (StringArray&) {} + static void addMethod (const String& base, const String& returnVal, const String& method, const String& initialContent, StringArray& baseClasses, StringArray& returnValues, @@ -160,9 +165,9 @@ protected: private: UndoManager undoManager; - int snapGridPixels; - bool snapActive, snapShown; - float componentOverlayOpacity; + int snapGridPixels = 8; + bool snapActive = true, snapShown = true; + float componentOverlayOpacity = 0.33f; StringArray activeExtraMethods; ScopedPointer currentXML; ScopedPointer userDocChangeTimer; @@ -172,6 +177,7 @@ private: void codeDocumentTextDeleted (int startIndex, int endIndex) override; void userEditedCpp(); bool documentAboutToClose (OpenDocumentManager::Document*) override; + void extractCustomPaintSnippetsFromCppFile (const String& cpp); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JucerDocument) }; diff --git a/extras/Projucer/Source/ComponentEditor/jucer_PaintRoutine.cpp b/extras/Projucer/Source/ComponentEditor/jucer_PaintRoutine.cpp index 97ee68bed2..0466503d86 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_PaintRoutine.cpp +++ b/extras/Projucer/Source/ComponentEditor/jucer_PaintRoutine.cpp @@ -293,16 +293,9 @@ void PaintRoutine::copySelectedToClipboard() XmlElement clip (clipboardXmlTag); - for (int i = 0; i < elements.size(); ++i) - { - PaintElement* const pe = elements.getUnchecked(i); - + for (auto* pe : elements) if (selectedElements.isSelected (pe)) - { - XmlElement* const e = pe->createXml(); - clip.addChildElement (e); - } - } + clip.addChildElement (pe->createXml()); SystemClipboard::copyTextToClipboard (clip.createDocument ("", false, false)); } @@ -325,8 +318,8 @@ void PaintRoutine::paste() void PaintRoutine::deleteSelected() { - const SelectedItemSet temp1 (selectedElements); - const SelectedItemSet temp2 (selectedPoints); + const SelectedItemSet temp1 (selectedElements); + const SelectedItemSet temp2 (selectedPoints); if (temp2.getNumSelected() > 0) { @@ -369,7 +362,7 @@ void PaintRoutine::selectAll() void PaintRoutine::selectedToFront() { - const SelectedItemSet temp (selectedElements); + const SelectedItemSet temp (selectedElements); for (int i = temp.getNumSelected(); --i >= 0;) elementToFront (temp.getSelectedItem(i), true); @@ -377,7 +370,7 @@ void PaintRoutine::selectedToFront() void PaintRoutine::selectedToBack() { - const SelectedItemSet temp (selectedElements); + const SelectedItemSet temp (selectedElements); for (int i = 0; i < temp.getNumSelected(); ++i) elementToBack (temp.getSelectedItem(i), true); @@ -399,11 +392,9 @@ void PaintRoutine::ungroupSelected() void PaintRoutine::bringLostItemsBackOnScreen (const Rectangle& parentArea) { - for (int i = 0; i < elements.size(); ++i) + for (auto* c : elements) { - PaintElement* const c = elements[i]; - - Rectangle r (c->getCurrentBounds (parentArea)); + auto r = c->getCurrentBounds (parentArea); if (! r.intersects (parentArea)) { @@ -415,11 +406,9 @@ void PaintRoutine::bringLostItemsBackOnScreen (const Rectangle& parentArea) void PaintRoutine::startDragging (const Rectangle& parentArea) { - for (int i = 0; i < elements.size(); ++i) + for (auto* c : elements) { - PaintElement* const c = elements[i]; - - Rectangle r (c->getCurrentBounds (parentArea)); + auto r = c->getCurrentBounds (parentArea); c->getProperties().set ("xDragStart", r.getX()); c->getProperties().set ("yDragStart", r.getY()); @@ -490,8 +479,8 @@ void PaintRoutine::drawElements (Graphics& g, const Rectangle& relativeTo) Component temp; temp.setBounds (relativeTo); - for (int i = 0; i < elements.size(); ++i) - elements.getUnchecked (i)->draw (g, getDocument()->getComponentLayout(), relativeTo); + for (auto* e : elements) + e->draw (g, getDocument()->getComponentLayout(), relativeTo); } //============================================================================== @@ -501,17 +490,16 @@ void PaintRoutine::dropImageAt (const File& f, int x, int y) if (d != nullptr) { - Rectangle bounds (d->getDrawableBounds()); + auto bounds = d->getDrawableBounds(); d = nullptr; - PaintElement* newElement - = addNewElement (ObjectTypes::createNewImageElement (this), -1, true); + auto* newElement = addNewElement (ObjectTypes::createNewImageElement (this), -1, true); - if (PaintElementImage* pei = dynamic_cast (newElement)) + if (auto* pei = dynamic_cast (newElement)) { String resourceName (getDocument()->getResources().findUniqueName (f.getFileName())); - if (const BinaryResources::BinaryResource* existingResource = getDocument()->getResources().getResourceForFile (f)) + if (auto* existingResource = getDocument()->getResources().getResourceForFile (f)) { resourceName = existingResource->name; } @@ -546,12 +534,11 @@ const char* PaintRoutine::xmlTagName = "BACKGROUND"; XmlElement* PaintRoutine::createXml() const { - XmlElement* const xml = new XmlElement (xmlTagName); - + auto* xml = new XmlElement (xmlTagName); xml->setAttribute ("backgroundColour", backgroundColour.toString()); - for (int i = 0; i < elements.size(); ++i) - xml->addChildElement (elements.getUnchecked (i)->createXml()); + for (auto* e : elements) + xml->addChildElement (e->createXml()); return xml; } @@ -565,7 +552,7 @@ bool PaintRoutine::loadFromXml (const XmlElement& xml) clear(); forEachXmlChildElement (xml, e) - if (PaintElement* const newElement = ObjectTypes::createElementForXml (e, this)) + if (auto* newElement = ObjectTypes::createElementForXml (e, this)) elements.add (newElement); return true; @@ -579,6 +566,12 @@ void PaintRoutine::fillInGeneratedCode (GeneratedCode& code, String& paintMethod if (! backgroundColour.isTransparent()) paintMethodCode << "g.fillAll (" << CodeHelpers::colourToCode (backgroundColour) << ");\n\n"; - for (int i = 0; i < elements.size(); ++i) - elements[i]->fillInGeneratedCode (code, paintMethodCode); + for (auto* e : elements) + e->fillInGeneratedCode (code, paintMethodCode); +} + +void PaintRoutine::applyCustomPaintSnippets (StringArray& snippets) +{ + for (auto* e : elements) + e->applyCustomPaintSnippets (snippets); } diff --git a/extras/Projucer/Source/ComponentEditor/jucer_PaintRoutine.h b/extras/Projucer/Source/ComponentEditor/jucer_PaintRoutine.h index 1d59cef1a9..6ffafe83ce 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_PaintRoutine.h +++ b/extras/Projucer/Source/ComponentEditor/jucer_PaintRoutine.h @@ -103,6 +103,8 @@ public: void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) const; + void applyCustomPaintSnippets (StringArray&); + //============================================================================== private: OwnedArray elements; diff --git a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_FillType.h b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_FillType.h index 4bdce9df65..8c539e39b7 100644 --- a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_FillType.h +++ b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_FillType.h @@ -117,58 +117,89 @@ public: } } - void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) const + String generateVariablesCode (String type) const { String s; switch (mode) { - case solidColour: - s << "g.setColour (" << CodeHelpers::colourToCode (colour) << ");\n"; - break; + case solidColour: + s << "Colour " << type << "Colour = " << CodeHelpers::colourToCode (colour) << ";\n"; + break; - case linearGradient: - case radialGradient: - { - String x1, y1, w, h, x2, y2; - positionToCode (gradPos1, code.document->getComponentLayout(), x1, y1, w, h); - positionToCode (gradPos2, code.document->getComponentLayout(), x2, y2, w, h); + case linearGradient: + case radialGradient: + s << "Colour " << type << "Colour1 = " << CodeHelpers::colourToCode (gradCol1) << ", " << type << "Colour2 = " << CodeHelpers::colourToCode (gradCol2) << ";\n"; + break; - s << "g.setGradientFill (ColourGradient ("; + case imageBrush: + break; - const String indent (String::repeatedString (" ", s.length())); + default: + jassertfalse; + break; + } - s << CodeHelpers::colourToCode (gradCol1) << ",\n" - << indent << castToFloat (x1) << ", " << castToFloat (y1) << ",\n" - << indent << CodeHelpers::colourToCode (gradCol2) << ",\n" - << indent << castToFloat (x2) << ", " << castToFloat (y2) << ",\n" - << indent << CodeHelpers::boolLiteral (mode == radialGradient) << "));\n"; + return s; + } + + void fillInGeneratedCode (String type, RelativePositionedRectangle relativeTo, GeneratedCode& code, String& paintMethodCode) const + { + String s; + + switch (mode) + { + case solidColour: + s << "g.setColour (" << type << "Colour);\n"; break; - } - case imageBrush: - { - const String imageVariable ("cachedImage_" + imageResourceName.replace ("::", "_") + "_" + String (code.getUniqueSuffix())); + case linearGradient: + case radialGradient: + { + String x0, y0, x1, y1, w, h, x2, y2; + positionToCode (relativeTo, code.document->getComponentLayout(), x0, y0, w, h); + positionToCode (gradPos1, code.document->getComponentLayout(), x1, y1, w, h); + positionToCode (gradPos2, code.document->getComponentLayout(), x2, y2, w, h); + + s << "g.setGradientFill (ColourGradient ("; + + auto indent = String::repeatedString (" ", s.length()); + + s << type << "Colour1,\n" + << indent << castToFloat (x1) << " - " << castToFloat (x0) << " + x,\n" + << indent << castToFloat (y1) << " - " << castToFloat (y0) << " + y,\n" + << indent << type << "Colour2,\n" + << indent << castToFloat (x2) << " - " << castToFloat (x0) << " + x,\n" + << indent << castToFloat (y2) << " - " << castToFloat (y0) << " + y,\n" + << indent << CodeHelpers::boolLiteral (mode == radialGradient) << "));\n"; + break; + } - code.addImageResourceLoader (imageVariable, imageResourceName); + case imageBrush: + { + auto imageVariable = "cachedImage_" + imageResourceName.replace ("::", "_") + "_" + String (code.getUniqueSuffix()); - String x, y, w, h; - positionToCode (imageAnchor, code.document->getComponentLayout(), x, y, w, h); + code.addImageResourceLoader (imageVariable, imageResourceName); - s << "g.setTiledImageFill ("; + String x0, y0, x1, y1, w, h; + positionToCode (relativeTo, code.document->getComponentLayout(), x0, y0, w, h); + positionToCode (imageAnchor, code.document->getComponentLayout(), x1, y1, w, h); - const String indent (String::repeatedString (" ", s.length())); + s << "g.setTiledImageFill ("; - s << imageVariable << ",\n" - << indent << x << ", " << y << ",\n" - << indent << CodeHelpers::floatLiteral (imageOpacity, 4) << ");\n"; + const String indent (String::repeatedString (" ", s.length())); - break; - } + s << imageVariable << ",\n" + << indent << x1 << " - " << x0 << " + x,\n" + << indent << y1 << " - " << y0 << " + y,\n" + << indent << CodeHelpers::floatLiteral (imageOpacity, 4) << ");\n"; - default: - jassertfalse; - break; + break; + } + + default: + jassertfalse; + break; } paintMethodCode += s; @@ -178,29 +209,29 @@ public: { switch (mode) { - case solidColour: - return "solid: " + colour.toString(); - - case linearGradient: - case radialGradient: - return (mode == linearGradient ? "linear: " - : " radial: ") - + gradPos1.toString() - + ", " - + gradPos2.toString() - + ", 0=" + gradCol1.toString() - + ", 1=" + gradCol2.toString(); - - case imageBrush: - return "image: " + imageResourceName.replaceCharacter (':', '#') - + ", " - + String (imageOpacity) - + ", " - + imageAnchor.toString(); - - default: - jassertfalse; - break; + case solidColour: + return "solid: " + colour.toString(); + + case linearGradient: + case radialGradient: + return (mode == linearGradient ? "linear: " + : " radial: ") + + gradPos1.toString() + + ", " + + gradPos2.toString() + + ", 0=" + gradCol1.toString() + + ", 1=" + gradCol2.toString(); + + case imageBrush: + return "image: " + imageResourceName.replaceCharacter (':', '#') + + ", " + + String (imageOpacity) + + ", " + + imageAnchor.toString(); + + default: + jassertfalse; + break; } return {}; diff --git a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElement.h b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElement.h index 9d56d664e6..0d24cd60b9 100644 --- a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElement.h +++ b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElement.h @@ -94,6 +94,8 @@ public: void changeListenerCallback (ChangeBroadcaster*); void parentHierarchyChanged(); + virtual void applyCustomPaintSnippets (StringArray&) {} + int borderThickness; protected: @@ -159,7 +161,7 @@ public: void changeListenerCallback (ChangeBroadcaster*) { jassert (propToRefresh != nullptr); - if (propToRefresh != nullptr) + if (propToRefresh != nullptr && owner != nullptr) propToRefresh->refresh(); } diff --git a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementEllipse.h b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementEllipse.h index 1a10384777..f8e935c45a 100644 --- a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementEllipse.h +++ b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementEllipse.h @@ -62,35 +62,53 @@ public: void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) { + if (fillType.isInvisible() && (strokeType.isInvisible() || ! isStrokePresent)) + return; + + String x, y, w, h, s; + positionToCode (position, code.document->getComponentLayout(), x, y, w, h); + + s << "{\n" + << " float x = " << castToFloat (x) << ", y = " << castToFloat (y) << ", " + << "width = " << castToFloat (w) << ", height = " << castToFloat (h) << ";\n"; + if (! fillType.isInvisible()) - { - String x, y, w, h, s; - positionToCode (position, code.document->getComponentLayout(), x, y, w, h); + s << " " << fillType.generateVariablesCode ("fill"); - fillType.fillInGeneratedCode (code, paintMethodCode); - s << "g.fillEllipse (" - << castToFloat (x) << ", " - << castToFloat (y) << ", " - << castToFloat (w) << ", " - << castToFloat (h) << ");\n\n"; + if (isStrokePresent && ! strokeType.isInvisible()) + s << " " << strokeType.fill.generateVariablesCode ("stroke"); - paintMethodCode += s; + s << " //[UserPaintCustomArguments] Customize the painting arguments here..\n" + << customPaintCode + << " //[/UserPaintCustomArguments]\n"; + + if (! fillType.isInvisible()) + { + s << " "; + fillType.fillInGeneratedCode ("fill", position, code, s); + s << " g.fillEllipse (x, y, width, height);\n"; } if (isStrokePresent && ! strokeType.isInvisible()) { - String x, y, w, h, s; - positionToCode (position, code.document->getComponentLayout(), x, y, w, h); - - strokeType.fill.fillInGeneratedCode (code, paintMethodCode); - s << "g.drawEllipse (" - << castToFloat (x) << ", " - << castToFloat (y) << ", " - << castToFloat (w) << ", " - << castToFloat (h) << ", " - << CodeHelpers::floatLiteral (strokeType.stroke.getStrokeThickness(), 3) << ");\n\n"; - - paintMethodCode += s; + s << " "; + strokeType.fill.fillInGeneratedCode ("stroke", position, code, s); + s << " g.drawEllipse (x, y, width, height, " << CodeHelpers::floatLiteral (strokeType.stroke.getStrokeThickness(), 3) << ");\n"; + } + + s << "}\n\n"; + + paintMethodCode += s; + } + + void applyCustomPaintSnippets (StringArray& snippets) + { + customPaintCode.clear(); + + if (! snippets.isEmpty() && (! fillType.isInvisible() || (isStrokePresent && ! strokeType.isInvisible()))) + { + customPaintCode = snippets[0]; + snippets.remove (0); } } @@ -131,10 +149,11 @@ public: } private: + String customPaintCode; + //============================================================================== - class ShapeToPathProperty : public ButtonPropertyComponent + struct ShapeToPathProperty : public ButtonPropertyComponent { - public: ShapeToPathProperty (PaintElementEllipse* const e) : ButtonPropertyComponent ("path", false), element (e) @@ -151,7 +170,6 @@ private: return "convert to a path"; } - private: - PaintElementEllipse* const element; + PaintElementEllipse* element; }; }; diff --git a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementGroup.h b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementGroup.h index 4fd36c4ee3..fb926664e5 100644 --- a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementGroup.h +++ b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementGroup.h @@ -209,12 +209,17 @@ public: return false; } + void applyCustomPaintSnippets (StringArray& snippets) + { + for (auto* e : subElements) + e->applyCustomPaintSnippets (snippets); + } + private: - OwnedArray subElements; + OwnedArray subElements; - class UngroupProperty : public ButtonPropertyComponent + struct UngroupProperty : public ButtonPropertyComponent { - public: UngroupProperty (PaintElementGroup* const e) : ButtonPropertyComponent ("ungroup", false), element (e) @@ -231,7 +236,6 @@ private: return "Ungroup"; } - private: - PaintElementGroup* const element; + PaintElementGroup* element; }; }; diff --git a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementImage.h b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementImage.h index dab593e462..2ca70c810b 100644 --- a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementImage.h +++ b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementImage.h @@ -95,10 +95,16 @@ public: void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) { - String r; - if (opacity > 0) { + String x, y, w, h, r; + positionToCode (position, getDocument()->getComponentLayout(), x, y, w, h); + r << "{\n" + << " int x = " << x << ", y = " << y << ", width = " << w << ", height = " << h << ";\n" + << " //[UserPaintCustomArguments] Customize the painting arguments here..\n" + << customPaintCode + << " //[/UserPaintCustomArguments]\n"; + if (dynamic_cast (getDrawable()) != 0) { const String imageVariable ("cachedImage_" + resourceName.replace ("::", "_") + "_" + String (code.getUniqueSuffix())); @@ -106,36 +112,32 @@ public: code.addImageResourceLoader (imageVariable, resourceName); if (opacity >= 254.0 / 255.0) - r << "g.setColour (Colours::black);\n"; + r << " g.setColour (Colours::black);\n"; else - r << "g.setColour (Colours::black.withAlpha (" << CodeHelpers::floatLiteral (opacity, 3) << "));\n"; + r << " g.setColour (Colours::black.withAlpha (" << CodeHelpers::floatLiteral (opacity, 3) << "));\n"; - String x, y, w, h; - positionToCode (position, getDocument()->getComponentLayout(), x, y, w, h); if (mode == stretched) { - r << "g.drawImage (" << imageVariable << ",\n " - << x << ", " << y << ", " << w << ", " << h - << ",\n 0, 0, " - << imageVariable << ".getWidth(), " - << imageVariable << ".getHeight());\n\n"; + r << " g.drawImage (" << imageVariable << ",\n" + << " x, y, width, height,\n" + << " 0, 0, " << imageVariable << ".getWidth(), " << imageVariable << ".getHeight());\n"; } else { - r << "g.drawImageWithin (" << imageVariable << ",\n " - << x << ", " << y << ", " << w << ", " << h - << ",\n "; + r << " g.drawImageWithin (" << imageVariable << ",\n" + << " x, y, width, height,\n" + << " "; if (mode == proportionalReducingOnly) r << "RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize"; else r << "RectanglePlacement::centred"; - r << ",\n false);\n\n"; + r << ",\n" + << " false);\n"; } - paintMethodCode += r; } else { @@ -154,28 +156,35 @@ public: << imageVariable << " = nullptr;\n"; if (opacity >= 254.0 / 255.0) - r << "g.setColour (Colours::black);\n"; + r << " g.setColour (Colours::black);\n"; else - r << "g.setColour (Colours::black.withAlpha (" << CodeHelpers::floatLiteral (opacity, 3) << "));\n"; - - String x, y, w, h; - positionToCode (position, code.document->getComponentLayout(), x, y, w, h); + r << " g.setColour (Colours::black.withAlpha (" << CodeHelpers::floatLiteral (opacity, 3) << "));\n"; - r << "jassert (" << imageVariable << " != 0);\n" - << "if (" << imageVariable << " != 0)\n " - << imageVariable << "->drawWithin (g, Rectangle (" - << x << ", " << y << ", " << w << ", " << h - << "),\n" - << String::repeatedString (" ", imageVariable.length() + 18) + r << " jassert (" << imageVariable << " != 0);\n" + << " if (" << imageVariable << " != 0)\n" + << " " << imageVariable << "->drawWithin (g, Rectangle (x, y, width, height),\n" + << " " << String::repeatedString (" ", imageVariable.length() + 18) << (mode == stretched ? "RectanglePlacement::stretchToFit" : (mode == proportionalReducingOnly ? "RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize" : "RectanglePlacement::centred")) - << ", " << CodeHelpers::floatLiteral (opacity, 3) - << ");\n\n"; - - paintMethodCode += r; + << ", " << CodeHelpers::floatLiteral (opacity, 3) << ");\n"; } } + + r << "}\n\n"; + + paintMethodCode += r; + } + } + + void applyCustomPaintSnippets (StringArray& snippets) + { + customPaintCode.clear(); + + if (! snippets.isEmpty() && opacity > 0) + { + customPaintCode = snippets[0]; + snippets.remove (0); } } @@ -385,6 +394,7 @@ private: String resourceName; double opacity; StretchMode mode; + String customPaintCode; //============================================================================== class ImageElementResourceProperty : public ImageResourceProperty diff --git a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementPath.cpp b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementPath.cpp index 51383a3b96..32318482df 100644 --- a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementPath.cpp +++ b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementPath.cpp @@ -382,10 +382,8 @@ void PaintElementPath::fillInGeneratedCode (GeneratedCode& code, String& paintMe if (! nonZeroWinding) r << pathVariable << ".setUsingNonZeroWinding (false);\n"; - for (int i = 0; i < points.size(); ++i) + for (auto* p : points) { - const PathPoint* const p = points.getUnchecked(i); - switch (p->type) { case Path::Iterator::startNewSubPath: @@ -400,15 +398,17 @@ void PaintElementPath::fillInGeneratedCode (GeneratedCode& code, String& paintMe case Path::Iterator::quadraticTo: r << pathVariable << ".quadraticTo (" << positionToPairOfValues (p->pos[0], layout) - << ", " << positionToPairOfValues (p->pos[1], layout) << ");\n"; + << ", " << positionToPairOfValues (p->pos[1], layout) << ");\n"; + somePointsAreRelative = somePointsAreRelative || ! p->pos[0].rect.isPositionAbsolute(); somePointsAreRelative = somePointsAreRelative || ! p->pos[1].rect.isPositionAbsolute(); break; case Path::Iterator::cubicTo: r << pathVariable << ".cubicTo (" << positionToPairOfValues (p->pos[0], layout) - << ", " << positionToPairOfValues (p->pos[1], layout) - << ", " << positionToPairOfValues (p->pos[2], layout) << ");\n"; + << ", " << positionToPairOfValues (p->pos[1], layout) + << ", " << positionToPairOfValues (p->pos[2], layout) << ");\n"; + somePointsAreRelative = somePointsAreRelative || ! p->pos[0].rect.isPositionAbsolute(); somePointsAreRelative = somePointsAreRelative || ! p->pos[1].rect.isPositionAbsolute(); somePointsAreRelative = somePointsAreRelative || ! p->pos[2].rect.isPositionAbsolute(); @@ -432,24 +432,50 @@ void PaintElementPath::fillInGeneratedCode (GeneratedCode& code, String& paintMe else code.constructorCode << r; + String s; + s << "{\n" + << " float x = 0, y = 0;\n"; + if (! fillType.isInvisible()) - { - fillType.fillInGeneratedCode (code, paintMethodCode); + s << " " << fillType.generateVariablesCode ("fill"); + + if (isStrokePresent && ! strokeType.isInvisible()) + s << " " << strokeType.fill.generateVariablesCode ("stroke"); + + s << " //[UserPaintCustomArguments] Customize the painting arguments here..\n" + << customPaintCode + << " //[/UserPaintCustomArguments]\n"; - paintMethodCode << "g.fillPath (" << pathVariable << ");\n"; + RelativePositionedRectangle zero; + + if (! fillType.isInvisible()) + { + s << " "; + fillType.fillInGeneratedCode ("fill", zero, code, s); + s << " g.fillPath (" << pathVariable << ", AffineTransform::translation(x, y));\n"; } if (isStrokePresent && ! strokeType.isInvisible()) { - String s; + s << " "; + strokeType.fill.fillInGeneratedCode ("stroke", zero, code, s); + s << " g.strokePath (" << pathVariable << ", " << strokeType.getPathStrokeCode() << ", AffineTransform::translation(x, y));\n"; + } - strokeType.fill.fillInGeneratedCode (code, s); - s << "g.strokePath (" << pathVariable << ", " << strokeType.getPathStrokeCode() << ");\n"; + s << "}\n\n"; - paintMethodCode += s; - } + paintMethodCode += s; +} + +void PaintElementPath::applyCustomPaintSnippets (StringArray& snippets) +{ + customPaintCode.clear(); - paintMethodCode += "\n"; + if (! snippets.isEmpty() && (! fillType.isInvisible() || (isStrokePresent && ! strokeType.isInvisible()))) + { + customPaintCode = snippets[0]; + snippets.remove(0); + } } //============================================================================== diff --git a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementPath.h b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementPath.h index 1142508db0..252f0fb346 100644 --- a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementPath.h +++ b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementPath.h @@ -101,6 +101,7 @@ public: void getEditableProperties (Array& props); void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode); + void applyCustomPaintSnippets (StringArray& snippets); //============================================================================== static const char* getTagName() noexcept { return "PATH"; } @@ -132,6 +133,7 @@ private: mutable Rectangle lastPathBounds; int mouseDownOnSegment; bool mouseDownSelectSegmentStatus; + String customPaintCode; String pathToString() const; void restorePathFromString (const String& s); diff --git a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementRectangle.h b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementRectangle.h index 8610456dd0..2e083957b7 100644 --- a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementRectangle.h +++ b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementRectangle.h @@ -76,27 +76,52 @@ public: void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) { + if (fillType.isInvisible() && (strokeType.isInvisible() || ! isStrokePresent)) + return; + + String x, y, w, h, s; + positionToCode (position, code.document->getComponentLayout(), x, y, w, h); + + s << "{\n" + << " int x = " << x << ", y = " << y << ", width = " << w << ", height = " << h << ";\n"; + if (! fillType.isInvisible()) - { - String x, y, w, h, s; - positionToCode (position, code.document->getComponentLayout(), x, y, w, h); + s << " " << fillType.generateVariablesCode ("fill"); - fillType.fillInGeneratedCode (code, paintMethodCode); - s << "g.fillRect (" << x << ", " << y << ", " << w << ", " << h << ");\n\n"; + if (isStrokePresent && ! strokeType.isInvisible()) + s << " " << strokeType.fill.generateVariablesCode ("stroke"); + + s << " //[UserPaintCustomArguments] Customize the painting arguments here..\n" + << customPaintCode + << " //[/UserPaintCustomArguments]\n"; - paintMethodCode += s; + if (! fillType.isInvisible()) + { + s << " "; + fillType.fillInGeneratedCode ("fill", position, code, s); + s << " g.fillRect (x, y, width, height);\n"; } if (isStrokePresent && ! strokeType.isInvisible()) { - String x, y, w, h, s; - positionToCode (position, code.document->getComponentLayout(), x, y, w, h); + s << " "; + strokeType.fill.fillInGeneratedCode ("stroke", position, code, s); + s << " g.drawRect (x, y, width, height, " << roundToInt (strokeType.stroke.getStrokeThickness()) << ");\n\n"; + } + + s << "}\n\n"; - strokeType.fill.fillInGeneratedCode (code, paintMethodCode); - s << "g.drawRect (" << x << ", " << y << ", " << w << ", " << h << ", " - << roundToInt (strokeType.stroke.getStrokeThickness()) << ");\n\n"; + paintMethodCode += s; + } - paintMethodCode += s; + void applyCustomPaintSnippets (StringArray& snippets) + { + customPaintCode.clear(); + + if (! snippets.isEmpty() && (! fillType.isInvisible() || (isStrokePresent && ! strokeType.isInvisible()))) + { + customPaintCode = snippets[0]; + snippets.remove (0); } } @@ -134,6 +159,8 @@ public: } private: + String customPaintCode; + class ShapeToPathProperty : public ButtonPropertyComponent { public: diff --git a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementRoundedRectangle.h b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementRoundedRectangle.h index f819304006..b61d877de5 100644 --- a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementRoundedRectangle.h +++ b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementRoundedRectangle.h @@ -116,37 +116,54 @@ public: //============================================================================== void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) { + if (fillType.isInvisible() && (strokeType.isInvisible() || ! isStrokePresent)) + return; + + String x, y, w, h, s; + positionToCode (position, code.document->getComponentLayout(), x, y, w, h); + + s << "{\n" + << " float x = " << castToFloat (x) << ", y = " << castToFloat (y) << ", " + << "width = " << castToFloat (w) << ", height = " << castToFloat (h) << ";\n"; + + if (! fillType.isInvisible()) + s << " " << fillType.generateVariablesCode ("fill"); + + if (isStrokePresent && ! strokeType.isInvisible()) + s << " " << strokeType.fill.generateVariablesCode ("stroke"); + + s << " //[UserPaintCustomArguments] Customize the painting arguments here..\n" + << customPaintCode + << " //[/UserPaintCustomArguments]\n"; + if (! fillType.isInvisible()) { - String x, y, w, h, s; - positionToCode (position, code.document->getComponentLayout(), x, y, w, h); - - fillType.fillInGeneratedCode (code, paintMethodCode); - s << "g.fillRoundedRectangle (" - << castToFloat (x) << ", " - << castToFloat (y) << ", " - << castToFloat (w) << ", " - << castToFloat (h) << ", " - << CodeHelpers::floatLiteral (cornerSize, 3) << ");\n\n"; - - paintMethodCode += s; + s << " "; + fillType.fillInGeneratedCode ("fill", position, code, s); + s << " g.fillRoundedRectangle (x, y, width, height, " << CodeHelpers::floatLiteral (cornerSize, 3) << ");\n"; } if (isStrokePresent && ! strokeType.isInvisible()) { - String x, y, w, h, s; - positionToCode (position, code.document->getComponentLayout(), x, y, w, h); - - strokeType.fill.fillInGeneratedCode (code, paintMethodCode); - s << "g.drawRoundedRectangle (" - << castToFloat (x) << ", " - << castToFloat (y) << ", " - << castToFloat (w) << ", " - << castToFloat (h) << ", " - << CodeHelpers::floatLiteral (cornerSize, 3) << ", " - << CodeHelpers::floatLiteral (strokeType.stroke.getStrokeThickness(), 3) << ");\n\n"; - - paintMethodCode += s; + s << " "; + strokeType.fill.fillInGeneratedCode ("stroke", position, code, s); + s << " g.drawRoundedRectangle (x, y, width, height, " << CodeHelpers::floatLiteral (cornerSize, 3) + << ", " << CodeHelpers::floatLiteral (strokeType.stroke.getStrokeThickness(), 3) << ");\n"; + } + + s << "}\n\n"; + + paintMethodCode += s; + } + + void applyCustomPaintSnippets (StringArray& snippets) + { + customPaintCode.clear(); + + if (! snippets.isEmpty() && (! fillType.isInvisible() || (isStrokePresent && ! strokeType.isInvisible()))) + { + customPaintCode = snippets[0]; + snippets.remove (0); } } @@ -191,6 +208,7 @@ public: private: double cornerSize; + String customPaintCode; //============================================================================== class CornerSizeProperty : public SliderPropertyComponent, diff --git a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementText.h b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementText.h index da5e09cd3a..6e433a978f 100644 --- a/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementText.h +++ b/extras/Projucer/Source/ComponentEditor/paintelements/jucer_PaintElementText.h @@ -83,27 +83,37 @@ public: { if (! fillType.isInvisible()) { - String r; - - fillType.fillInGeneratedCode (code, paintMethodCode); - - String x, y, w, h; + String x, y, w, h, r; positionToCode (position, code.document->getComponentLayout(), x, y, w, h); - - r << "g.setFont (" - << FontPropertyComponent::getCompleteFontCode (font, typefaceName) - << ");\ng.drawText (" - << quotedString (text, code.shouldUseTransMacro()) - << ",\n " - << x << ", " << y << ", " << w << ", " << h - << ",\n " - << CodeHelpers::justificationToCode (justification) - << ", true);\n\n"; - + 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) + { + customPaintCode.clear(); + + if (! snippets.isEmpty() && ! fillType.isInvisible()) + { + customPaintCode = snippets[0]; + snippets.remove (0); + } + } + static const char* getTagName() noexcept { return "TEXT"; } XmlElement* createXml() const @@ -376,7 +386,8 @@ private: Font font; String typefaceName; Justification justification; - + String customPaintCode; + Array justificationTypes; //============================================================================== diff --git a/extras/Projucer/Source/ComponentEditor/ui/jucer_JucerDocumentEditor.cpp b/extras/Projucer/Source/ComponentEditor/ui/jucer_JucerDocumentEditor.cpp index 1192d1076f..3bbefd013d 100644 --- a/extras/Projucer/Source/ComponentEditor/ui/jucer_JucerDocumentEditor.cpp +++ b/extras/Projucer/Source/ComponentEditor/ui/jucer_JucerDocumentEditor.cpp @@ -318,11 +318,7 @@ static SourceCodeEditor* createCodeEditor (const File& file, SourceCodeDocument& //============================================================================== JucerDocumentEditor::JucerDocumentEditor (JucerDocument* const doc) : document (doc), - tabbedComponent (TabbedButtonBar::TabsAtTop), - compLayoutPanel (0), - lastViewportX (0), - lastViewportY (0), - currentZoomLevel (1.0) + tabbedComponent (doc) { setOpaque (true); @@ -1028,9 +1024,7 @@ bool JucerDocumentEditor::perform (const InvocationInfo& info) case StandardApplicationCommandIDs::paste: { - ScopedPointer doc (XmlDocument::parse (SystemClipboard::getTextFromClipboard())); - - if (doc != nullptr) + if (ScopedPointer doc = XmlDocument::parse (SystemClipboard::getTextFromClipboard())) { if (doc->hasTagName (ComponentLayout::clipboardXmlTag)) { @@ -1095,9 +1089,8 @@ bool JucerDocumentEditor::keyPressed (const KeyPress& key) JucerDocumentEditor* JucerDocumentEditor::getActiveDocumentHolder() { ApplicationCommandInfo info (0); - ApplicationCommandTarget* target = ProjucerApplication::getCommandManager().getTargetForCommand (JucerCommandIDs::editCompLayout, info); - - return dynamic_cast (target); + return dynamic_cast (ProjucerApplication::getCommandManager() + .getTargetForCommand (JucerCommandIDs::editCompLayout, info)); } Image JucerDocumentEditor::createComponentLayerSnapshot() const @@ -1105,7 +1098,7 @@ Image JucerDocumentEditor::createComponentLayerSnapshot() const if (compLayoutPanel != nullptr) return compLayoutPanel->createComponentSnapshot(); - return Image(); + return {}; } const int gridSnapMenuItemBase = 0x8723620; @@ -1187,13 +1180,13 @@ void createGUIEditorMenu (PopupMenu& menu) void handleGUIEditorMenuCommand (int menuItemID) { - if (JucerDocumentEditor* ed = JucerDocumentEditor::getActiveDocumentHolder()) + if (auto* ed = JucerDocumentEditor::getActiveDocumentHolder()) { int gridIndex = menuItemID - gridSnapMenuItemBase; if (isPositiveAndBelow (gridIndex, numElementsInArray (snapSizes))) { - JucerDocument& doc = *ed->getDocument(); + auto& doc = *ed->getDocument(); doc.setSnappingGrid (snapSizes [gridIndex], doc.isSnapActive (false), diff --git a/extras/Projucer/Source/ComponentEditor/ui/jucer_JucerDocumentEditor.h b/extras/Projucer/Source/ComponentEditor/ui/jucer_JucerDocumentEditor.h index 29ea28774e..0318808cbe 100644 --- a/extras/Projucer/Source/ComponentEditor/ui/jucer_JucerDocumentEditor.h +++ b/extras/Projucer/Source/ComponentEditor/ui/jucer_JucerDocumentEditor.h @@ -58,28 +58,37 @@ public: Image createComponentLayerSnapshot() const; //============================================================================== - void paint (Graphics& g); - void resized(); - void changeListenerCallback (ChangeBroadcaster*); - bool keyPressed (const KeyPress&); + void paint (Graphics& g) override; + void resized() override; + void changeListenerCallback (ChangeBroadcaster*) override; + bool keyPressed (const KeyPress&) override; //============================================================================== - ApplicationCommandTarget* getNextCommandTarget(); - void getAllCommands (Array &); - void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result); - bool perform (const InvocationInfo&); + ApplicationCommandTarget* getNextCommandTarget() override; + void getAllCommands (Array&) override; + void getCommandInfo (CommandID, ApplicationCommandInfo&) override; + bool perform (const InvocationInfo&) override; static JucerDocumentEditor* getActiveDocumentHolder(); private: ScopedPointer document; - TabbedComponent tabbedComponent; - ComponentLayoutPanel* compLayoutPanel; + ComponentLayoutPanel* compLayoutPanel = nullptr; - bool isSomethingSelected() const; - int lastViewportX, lastViewportY; + struct JucerDocumentTabs : public TabbedComponent + { + JucerDocumentTabs (JucerDocument* d) : TabbedComponent (TabbedButtonBar::TabsAtTop), document (d) {} + void currentTabChanged (int, const String&) override { document->refreshCustomCodeFromDocument(); } + + JucerDocument* document; + }; + + JucerDocumentTabs tabbedComponent; - double currentZoomLevel; + int lastViewportX = 0, lastViewportY = 0; + double currentZoomLevel = 1.0; + + bool isSomethingSelected() const; // only non-zero if a layout tab is selected ComponentLayout* getCurrentLayout() const; @@ -89,6 +98,6 @@ private: void setZoom (double scale); double getZoom() const; - void addElement (const int index); - void addComponent (const int index); + void addElement (int index); + void addComponent (int index); }; diff --git a/extras/Projucer/Source/Utility/jucer_CodeHelpers.cpp b/extras/Projucer/Source/Utility/jucer_CodeHelpers.cpp index d3268fcfc7..a465a9e004 100644 --- a/extras/Projucer/Source/Utility/jucer_CodeHelpers.cpp +++ b/extras/Projucer/Source/Utility/jucer_CodeHelpers.cpp @@ -36,23 +36,39 @@ namespace CodeHelpers if (numSpaces == 0) return code; - const String space (String::repeatedString (" ", numSpaces)); + auto space = String::repeatedString (" ", numSpaces); + auto lines = StringArray::fromLines (code); - StringArray lines; - lines.addLines (code); - - for (int i = (indentFirstLine ? 0 : 1); i < lines.size(); ++i) + for (auto& line : lines) { - String s (lines[i].trimEnd()); - if (s.isNotEmpty()) - s = space + s; + if (! indentFirstLine) + { + indentFirstLine = true; + continue; + } - lines.set (i, s); + if (line.trimEnd().isNotEmpty()) + line = space + line; } return lines.joinIntoString (newLine); } + String unindent (const String& code, const int numSpaces) + { + if (numSpaces == 0) + return code; + + auto space = String::repeatedString (" ", numSpaces); + auto lines = StringArray::fromLines (code); + + for (auto& line : lines) + if (line.startsWith (space)) + line = line.substring (numSpaces); + + return lines.joinIntoString (newLine); + } + String makeValidIdentifier (String s, bool capitalise, bool removeColons, bool allowTemplates) { if (s.isEmpty()) diff --git a/extras/Projucer/Source/Utility/jucer_CodeHelpers.h b/extras/Projucer/Source/Utility/jucer_CodeHelpers.h index 1744ca7d72..5efa7aa737 100644 --- a/extras/Projucer/Source/Utility/jucer_CodeHelpers.h +++ b/extras/Projucer/Source/Utility/jucer_CodeHelpers.h @@ -30,7 +30,8 @@ //============================================================================== namespace CodeHelpers { - String indent (const String& code, const int numSpaces, bool indentFirstLine); + String indent (const String& code, int numSpaces, bool indentFirstLine); + String unindent (const String& code, int numSpaces); String makeValidIdentifier (String s, bool capitalise, bool removeColons, bool allowTemplates); String createIncludeStatement (const File& includedFile, const File& targetFile); String createIncludeStatement (const String& includePath); @@ -41,7 +42,7 @@ namespace CodeHelpers String floatLiteral (double value, int numDecPlaces); String boolLiteral (bool value); - String colourToCode (Colour col); + String colourToCode (Colour); String justificationToCode (Justification); String alignFunctionCallParams (const String& call, const StringArray& parameters, int maxLineLength); @@ -50,7 +51,7 @@ namespace CodeHelpers bool breakAtNewLines, bool allowStringBreaks); void createStringMatcher (OutputStream& out, const String& utf8PointerVariable, - const StringArray& strings, const StringArray& codeToExecute, const int indentLevel); + const StringArray& strings, const StringArray& codeToExecute, int indentLevel); String getLeadingWhitespace (String line); int getBraceCount (String::CharPointerType line);