Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

juce_Drawable.cpp 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. Drawable::Drawable()
  22. {
  23. setInterceptsMouseClicks (false, false);
  24. setPaintingIsUnclipped (true);
  25. }
  26. Drawable::Drawable (const Drawable& other)
  27. : Component (other.getName())
  28. {
  29. setInterceptsMouseClicks (false, false);
  30. setPaintingIsUnclipped (true);
  31. setComponentID (other.getComponentID());
  32. setTransform (other.getTransform());
  33. }
  34. Drawable::~Drawable()
  35. {
  36. }
  37. void Drawable::applyDrawableClipPath (Graphics& g)
  38. {
  39. if (drawableClipPath != nullptr)
  40. {
  41. auto clipPath = drawableClipPath->getOutlineAsPath();
  42. if (! clipPath.isEmpty())
  43. g.getInternalContext().clipToPath (clipPath, {});
  44. }
  45. }
  46. //==============================================================================
  47. void Drawable::draw (Graphics& g, float opacity, const AffineTransform& transform) const
  48. {
  49. const_cast<Drawable*> (this)->nonConstDraw (g, opacity, transform);
  50. }
  51. void Drawable::nonConstDraw (Graphics& g, float opacity, const AffineTransform& transform)
  52. {
  53. Graphics::ScopedSaveState ss (g);
  54. g.addTransform (AffineTransform::translation ((float) -(originRelativeToComponent.x),
  55. (float) -(originRelativeToComponent.y))
  56. .followedBy (getTransform())
  57. .followedBy (transform));
  58. applyDrawableClipPath (g);
  59. if (! g.isClipEmpty())
  60. {
  61. if (opacity < 1.0f)
  62. {
  63. g.beginTransparencyLayer (opacity);
  64. paintEntireComponent (g, true);
  65. g.endTransparencyLayer();
  66. }
  67. else
  68. {
  69. paintEntireComponent (g, true);
  70. }
  71. }
  72. }
  73. void Drawable::drawAt (Graphics& g, float x, float y, float opacity) const
  74. {
  75. draw (g, opacity, AffineTransform::translation (x, y));
  76. }
  77. void Drawable::drawWithin (Graphics& g, Rectangle<float> destArea,
  78. RectanglePlacement placement, float opacity) const
  79. {
  80. draw (g, opacity, placement.getTransformToFit (getDrawableBounds(), destArea));
  81. }
  82. //==============================================================================
  83. DrawableComposite* Drawable::getParent() const
  84. {
  85. return dynamic_cast<DrawableComposite*> (getParentComponent());
  86. }
  87. void Drawable::setClipPath (Drawable* clipPath)
  88. {
  89. if (drawableClipPath != clipPath)
  90. {
  91. drawableClipPath = clipPath;
  92. repaint();
  93. }
  94. }
  95. void Drawable::transformContextToCorrectOrigin (Graphics& g)
  96. {
  97. g.setOrigin (originRelativeToComponent);
  98. }
  99. void Drawable::parentHierarchyChanged()
  100. {
  101. setBoundsToEnclose (getDrawableBounds());
  102. }
  103. void Drawable::setBoundsToEnclose (Rectangle<float> area)
  104. {
  105. Point<int> parentOrigin;
  106. if (auto* parent = getParent())
  107. parentOrigin = parent->originRelativeToComponent;
  108. auto newBounds = area.getSmallestIntegerContainer() + parentOrigin;
  109. originRelativeToComponent = parentOrigin - newBounds.getPosition();
  110. setBounds (newBounds);
  111. }
  112. //==============================================================================
  113. bool Drawable::replaceColour (Colour original, Colour replacement)
  114. {
  115. bool changed = false;
  116. for (auto* c : getChildren())
  117. if (auto* d = dynamic_cast<Drawable*> (c))
  118. changed = d->replaceColour (original, replacement) || changed;
  119. return changed;
  120. }
  121. //==============================================================================
  122. void Drawable::setOriginWithOriginalSize (Point<float> originWithinParent)
  123. {
  124. setTransform (AffineTransform::translation (originWithinParent.x, originWithinParent.y));
  125. }
  126. void Drawable::setTransformToFit (const Rectangle<float>& area, RectanglePlacement placement)
  127. {
  128. if (! area.isEmpty())
  129. setTransform (placement.getTransformToFit (getDrawableBounds(), area));
  130. }
  131. //==============================================================================
  132. Drawable* Drawable::createFromImageData (const void* data, const size_t numBytes)
  133. {
  134. Drawable* result = nullptr;
  135. auto image = ImageFileFormat::loadFrom (data, numBytes);
  136. if (image.isValid())
  137. {
  138. auto* di = new DrawableImage();
  139. di->setImage (image);
  140. result = di;
  141. }
  142. else
  143. {
  144. auto asString = String::createStringFromData (data, (int) numBytes);
  145. XmlDocument doc (asString);
  146. ScopedPointer<XmlElement> outer (doc.getDocumentElement (true));
  147. if (outer != nullptr && outer->hasTagName ("svg"))
  148. {
  149. ScopedPointer<XmlElement> svg (doc.getDocumentElement());
  150. if (svg != nullptr)
  151. result = Drawable::createFromSVG (*svg);
  152. }
  153. }
  154. return result;
  155. }
  156. Drawable* Drawable::createFromImageDataStream (InputStream& dataSource)
  157. {
  158. MemoryOutputStream mo;
  159. mo << dataSource;
  160. return createFromImageData (mo.getData(), mo.getDataSize());
  161. }
  162. Drawable* Drawable::createFromImageFile (const File& file)
  163. {
  164. FileInputStream fin (file);
  165. return fin.openedOk() ? createFromImageDataStream (fin) : nullptr;
  166. }
  167. //==============================================================================
  168. template <class DrawableClass>
  169. struct DrawableTypeHandler : public ComponentBuilder::TypeHandler
  170. {
  171. DrawableTypeHandler() : ComponentBuilder::TypeHandler (DrawableClass::valueTreeType)
  172. {
  173. }
  174. Component* addNewComponentFromState (const ValueTree& state, Component* parent)
  175. {
  176. auto* d = new DrawableClass();
  177. if (parent != nullptr)
  178. parent->addAndMakeVisible (d);
  179. updateComponentFromState (d, state);
  180. return d;
  181. }
  182. void updateComponentFromState (Component* component, const ValueTree& state)
  183. {
  184. if (auto* d = dynamic_cast<DrawableClass*> (component))
  185. d->refreshFromValueTree (state, *this->getBuilder());
  186. else
  187. jassertfalse;
  188. }
  189. };
  190. void Drawable::registerDrawableTypeHandlers (ComponentBuilder& builder)
  191. {
  192. builder.registerTypeHandler (new DrawableTypeHandler<DrawablePath>());
  193. builder.registerTypeHandler (new DrawableTypeHandler<DrawableComposite>());
  194. builder.registerTypeHandler (new DrawableTypeHandler<DrawableRectangle>());
  195. builder.registerTypeHandler (new DrawableTypeHandler<DrawableImage>());
  196. builder.registerTypeHandler (new DrawableTypeHandler<DrawableText>());
  197. }
  198. Drawable* Drawable::createFromValueTree (const ValueTree& tree, ComponentBuilder::ImageProvider* imageProvider)
  199. {
  200. ComponentBuilder builder (tree);
  201. builder.setImageProvider (imageProvider);
  202. registerDrawableTypeHandlers (builder);
  203. ScopedPointer<Component> comp (builder.createComponent());
  204. auto* d = dynamic_cast<Drawable*> (static_cast<Component*> (comp));
  205. if (d != nullptr)
  206. comp.release();
  207. return d;
  208. }
  209. //==============================================================================
  210. Drawable::ValueTreeWrapperBase::ValueTreeWrapperBase (const ValueTree& s) : state (s)
  211. {
  212. }
  213. String Drawable::ValueTreeWrapperBase::getID() const
  214. {
  215. return state [ComponentBuilder::idProperty];
  216. }
  217. void Drawable::ValueTreeWrapperBase::setID (const String& newID)
  218. {
  219. if (newID.isEmpty())
  220. state.removeProperty (ComponentBuilder::idProperty, nullptr);
  221. else
  222. state.setProperty (ComponentBuilder::idProperty, newID, nullptr);
  223. }
  224. } // namespace juce