|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2015 - ROLI Ltd.
-
- Permission is granted to use this software under the terms of either:
- a) the GPL v2 (or any later version)
- b) the Affero GPL v3
-
- Details of these licenses can be found at: www.gnu.org/licenses
-
- JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- ------------------------------------------------------------------------------
-
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.juce.com for more information.
-
- ==============================================================================
- */
-
- #pragma once
-
- #include "../jucer_PaintRoutine.h"
- #include "../properties/jucer_FilePropertyComponent.h"
- #include "jucer_ImageResourceProperty.h"
- #include "jucer_PaintElementUndoableAction.h"
-
-
- //==============================================================================
- class PaintElementImage : public PaintElement
- {
- public:
- PaintElementImage (PaintRoutine* pr)
- : PaintElement (pr, "Image"),
- opacity (1.0),
- mode (stretched)
- {
- }
-
- enum StretchMode
- {
- stretched = 0,
- proportional = 1,
- proportionalReducingOnly = 2
- };
-
- const Drawable* getDrawable()
- {
- if (JucerDocument* const document = getDocument())
- return document->getResources().getDrawable (resourceName);
-
- return nullptr;
- }
-
- void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
- {
- const Rectangle<int> r (position.getRectangle (parentArea, layout));
-
- if (const Drawable* const image = getDrawable())
- {
- image->drawWithin (g, r.toFloat(),
- mode == stretched ? RectanglePlacement::stretchToFit
- : (mode == proportionalReducingOnly ? (RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize)
- : RectanglePlacement::centred),
- (float) opacity);
- }
- else
- {
- g.setColour (Colours::grey.withAlpha (0.5f));
- g.fillRect (r);
-
- g.setColour (Colours::black);
- g.drawText ("(image missing)",
- r.getX(), r.getY(), r.getWidth(), r.getHeight(),
- Justification::centred, true);
- }
- }
-
- //==============================================================================
- void getEditableProperties (Array <PropertyComponent*>& props)
- {
- PaintElement::getEditableProperties (props);
-
- props.add (new ImageElementResourceProperty (this));
- props.add (new StretchModeProperty (this));
- props.add (new OpacityProperty (this));
- props.add (new ResetSizeProperty (this));
- }
-
- void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
- {
- String r;
-
- if (opacity > 0)
- {
- if (dynamic_cast<const DrawableImage*> (getDrawable()) != 0)
- {
- const String imageVariable ("cachedImage_" + resourceName.replace ("::", "_") + "_" + String (code.getUniqueSuffix()));
-
- code.addImageResourceLoader (imageVariable, resourceName);
-
- if (opacity >= 254.0 / 255.0)
- 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, 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";
- }
- else
- {
- r << "g.drawImageWithin (" << imageVariable << ",\n "
- << x << ", " << y << ", " << w << ", " << h
- << ",\n ";
-
- if (mode == proportionalReducingOnly)
- r << "RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize";
- else
- r << "RectanglePlacement::centred";
-
- r << ",\n false);\n\n";
- }
-
- paintMethodCode += r;
- }
- else
- {
- if (resourceName.isNotEmpty())
- {
- const String imageVariable ("drawable" + String (code.getUniqueSuffix()));
-
- code.privateMemberDeclarations
- << "ScopedPointer<Drawable> " << imageVariable << ";\n";
-
- code.constructorCode
- << imageVariable << " = Drawable::createFromImageData ("
- << resourceName << ", " << resourceName << "Size);\n";
-
- code.destructorCode
- << imageVariable << " = nullptr;\n";
-
- if (opacity >= 254.0 / 255.0)
- 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 << "jassert (" << imageVariable << " != 0);\n"
- << "if (" << imageVariable << " != 0)\n "
- << imageVariable << "->drawWithin (g, Rectangle<float> ("
- << x << ", " << y << ", " << w << ", " << h
- << "),\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;
- }
- }
- }
- }
-
- //==============================================================================
- class SetResourceAction : public PaintElementUndoableAction <PaintElementImage>
- {
- public:
- SetResourceAction (PaintElementImage* const element, const String& newResource_)
- : PaintElementUndoableAction <PaintElementImage> (element),
- newResource (newResource_)
- {
- oldResource = element->getResource();
- }
-
- bool perform()
- {
- showCorrectTab();
- getElement()->setResource (newResource, false);
- return true;
- }
-
- bool undo()
- {
- showCorrectTab();
- getElement()->setResource (oldResource, false);
- return true;
- }
-
- private:
- String newResource, oldResource;
- };
-
- void setResource (const String& newName, const bool undoable)
- {
- if (resourceName != newName)
- {
- if (undoable)
- {
- perform (new SetResourceAction (this, newName),
- "Change image resource");
- }
- else
- {
- resourceName = newName;
- changed();
- }
- }
-
- repaint();
- }
-
- String getResource() const
- {
- return resourceName;
- }
-
- //==============================================================================
- class SetOpacityAction : public PaintElementUndoableAction <PaintElementImage>
- {
- public:
- SetOpacityAction (PaintElementImage* const element, const double newOpacity_)
- : PaintElementUndoableAction <PaintElementImage> (element),
- newOpacity (newOpacity_)
- {
- oldOpacity = element->getOpacity();
- }
-
- bool perform()
- {
- showCorrectTab();
- getElement()->setOpacity (newOpacity, false);
- return true;
- }
-
- bool undo()
- {
- showCorrectTab();
- getElement()->setOpacity (oldOpacity, false);
- return true;
- }
-
- private:
- double newOpacity, oldOpacity;
- };
-
- void setOpacity (double newOpacity, const bool undoable)
- {
- newOpacity = jlimit (0.0, 1.0, newOpacity);
-
- if (opacity != newOpacity)
- {
- if (undoable)
- {
- perform (new SetOpacityAction (this, newOpacity),
- "Change image opacity");
- }
- else
- {
- opacity = newOpacity;
- changed();
- }
- }
- }
-
- double getOpacity() const noexcept { return opacity; }
-
- //==============================================================================
- static const char* getTagName() noexcept { return "IMAGE"; }
-
- void resetToImageSize()
- {
- if (const Drawable* const image = getDrawable())
- {
- if (PaintRoutineEditor* ed = dynamic_cast<PaintRoutineEditor*> (getParentComponent()))
- {
- const Rectangle<int> parentArea (ed->getComponentArea());
-
- Rectangle<int> r (getCurrentBounds (parentArea));
- Rectangle<float> b (image->getDrawableBounds());
-
- r.setSize ((int) (b.getWidth() + 0.999f),
- (int) (b.getHeight() + 0.999f));
-
- setCurrentBounds (r, parentArea, true);
- }
- }
- }
-
- //==============================================================================
- class SetStretchModeAction : public PaintElementUndoableAction <PaintElementImage>
- {
- public:
- SetStretchModeAction (PaintElementImage* const element, const StretchMode newValue_)
- : PaintElementUndoableAction <PaintElementImage> (element),
- newValue (newValue_)
- {
- oldValue = element->getStretchMode();
- }
-
- bool perform()
- {
- showCorrectTab();
- getElement()->setStretchMode (newValue, false);
- return true;
- }
-
- bool undo()
- {
- showCorrectTab();
- getElement()->setStretchMode (oldValue, false);
- return true;
- }
-
- private:
- StretchMode newValue, oldValue;
- };
-
- StretchMode getStretchMode() const noexcept { return mode; }
-
- void setStretchMode (const StretchMode newMode, const bool undoable)
- {
- if (mode != newMode)
- {
- if (undoable)
- {
- perform (new SetStretchModeAction (this, newMode),
- "Change image mode");
- }
- else
- {
- mode = newMode;
- changed();
- }
- }
- }
-
- //==============================================================================
- XmlElement* createXml() const
- {
- XmlElement* e = new XmlElement (getTagName());
- position.applyToXml (*e);
- e->setAttribute ("resource", resourceName);
- e->setAttribute ("opacity", opacity);
- e->setAttribute ("mode", (int) mode);
-
- return e;
- }
-
- bool loadFromXml (const XmlElement& xml)
- {
- if (xml.hasTagName (getTagName()))
- {
- position.restoreFromXml (xml, position);
- resourceName = xml.getStringAttribute ("resource", String());
- opacity = xml.getDoubleAttribute ("opacity", 1.0);
- mode = (StretchMode) xml.getIntAttribute ("mode", (int) stretched);
-
- repaint();
- return true;
- }
-
- jassertfalse;
- return false;
- }
-
- private:
- String resourceName;
- double opacity;
- StretchMode mode;
-
- //==============================================================================
- class ImageElementResourceProperty : public ImageResourceProperty <PaintElementImage>
- {
- public:
- ImageElementResourceProperty (PaintElementImage* const e)
- : ImageResourceProperty <PaintElementImage> (e, "image source")
- {
- }
-
- void setResource (const String& newName)
- {
- if (element != nullptr)
- element->setResource (newName, true);
- }
-
- String getResource() const
- {
- if (element != nullptr)
- return element->getResource();
-
- return {};
- }
- };
-
- //==============================================================================
- class OpacityProperty : public SliderPropertyComponent
- {
- public:
- OpacityProperty (PaintElementImage* const e)
- : SliderPropertyComponent ("opacity", 0.0, 1.0, 0.001),
- listener (e)
- {
- listener.setPropertyToRefresh (*this);
- }
-
- void setValue (double newValue)
- {
- listener.owner->getDocument()->getUndoManager().undoCurrentTransactionOnly();
- listener.owner->setOpacity (newValue, true);
- }
-
- double getValue() const
- {
- return listener.owner->getOpacity();
- }
-
- ElementListener<PaintElementImage> listener;
- };
-
- class StretchModeProperty : public ChoicePropertyComponent
- {
- public:
- StretchModeProperty (PaintElementImage* const e)
- : ChoicePropertyComponent ("stretch mode"),
- listener (e)
- {
- listener.setPropertyToRefresh (*this);
-
- choices.add ("Stretched to fit");
- choices.add ("Maintain aspect ratio");
- choices.add ("Maintain aspect ratio, only reduce in size");
- }
-
- void setIndex (int newIndex)
- {
- listener.owner->setStretchMode ((StretchMode) newIndex, true);
- }
-
- int getIndex() const
- {
- return (int) listener.owner->getStretchMode();
- }
-
- ElementListener<PaintElementImage> listener;
- };
-
- class ResetSizeProperty : public ButtonPropertyComponent
- {
- public:
- ResetSizeProperty (PaintElementImage* const e)
- : ButtonPropertyComponent ("reset", false),
- element (e)
- {
- }
-
- void buttonClicked()
- {
- element->resetToImageSize();
- }
-
- String getButtonText() const { return "reset to image size"; }
-
- private:
- PaintElementImage* const element;
- };
- };
|