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.

278 lines
8.2KB

  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. Drawable::Drawable()
  20. {
  21. setInterceptsMouseClicks (false, false);
  22. setPaintingIsUnclipped (true);
  23. }
  24. Drawable::Drawable (const Drawable& other)
  25. : Component (other.getName())
  26. {
  27. setInterceptsMouseClicks (false, false);
  28. setPaintingIsUnclipped (true);
  29. setComponentID (other.getComponentID());
  30. setTransform (other.getTransform());
  31. }
  32. Drawable::~Drawable()
  33. {
  34. }
  35. void Drawable::applyDrawableClipPath (Graphics& g)
  36. {
  37. if (drawableClipPath != nullptr)
  38. {
  39. auto clipPath = drawableClipPath->getOutlineAsPath();
  40. if (! clipPath.isEmpty())
  41. g.getInternalContext().clipToPath (clipPath, {});
  42. }
  43. }
  44. //==============================================================================
  45. void Drawable::draw (Graphics& g, float opacity, const AffineTransform& transform) const
  46. {
  47. const_cast<Drawable*> (this)->nonConstDraw (g, opacity, transform);
  48. }
  49. void Drawable::nonConstDraw (Graphics& g, float opacity, const AffineTransform& transform)
  50. {
  51. Graphics::ScopedSaveState ss (g);
  52. g.addTransform (AffineTransform::translation ((float) -(originRelativeToComponent.x),
  53. (float) -(originRelativeToComponent.y))
  54. .followedBy (getTransform())
  55. .followedBy (transform));
  56. applyDrawableClipPath (g);
  57. if (! g.isClipEmpty())
  58. {
  59. if (opacity < 1.0f)
  60. {
  61. g.beginTransparencyLayer (opacity);
  62. paintEntireComponent (g, true);
  63. g.endTransparencyLayer();
  64. }
  65. else
  66. {
  67. paintEntireComponent (g, true);
  68. }
  69. }
  70. }
  71. void Drawable::drawAt (Graphics& g, float x, float y, float opacity) const
  72. {
  73. draw (g, opacity, AffineTransform::translation (x, y));
  74. }
  75. void Drawable::drawWithin (Graphics& g, Rectangle<float> destArea,
  76. RectanglePlacement placement, float opacity) const
  77. {
  78. draw (g, opacity, placement.getTransformToFit (getDrawableBounds(), destArea));
  79. }
  80. //==============================================================================
  81. DrawableComposite* Drawable::getParent() const
  82. {
  83. return dynamic_cast<DrawableComposite*> (getParentComponent());
  84. }
  85. void Drawable::setClipPath (Drawable* clipPath)
  86. {
  87. if (drawableClipPath != clipPath)
  88. {
  89. drawableClipPath = clipPath;
  90. repaint();
  91. }
  92. }
  93. void Drawable::transformContextToCorrectOrigin (Graphics& g)
  94. {
  95. g.setOrigin (originRelativeToComponent);
  96. }
  97. void Drawable::parentHierarchyChanged()
  98. {
  99. setBoundsToEnclose (getDrawableBounds());
  100. }
  101. void Drawable::setBoundsToEnclose (Rectangle<float> area)
  102. {
  103. Point<int> parentOrigin;
  104. if (auto* parent = getParent())
  105. parentOrigin = parent->originRelativeToComponent;
  106. auto newBounds = area.getSmallestIntegerContainer() + parentOrigin;
  107. originRelativeToComponent = parentOrigin - newBounds.getPosition();
  108. setBounds (newBounds);
  109. }
  110. //==============================================================================
  111. bool Drawable::replaceColour (Colour original, Colour replacement)
  112. {
  113. bool changed = false;
  114. for (auto* c : getChildren())
  115. if (auto* d = dynamic_cast<Drawable*> (c))
  116. changed = d->replaceColour (original, replacement) || changed;
  117. return changed;
  118. }
  119. //==============================================================================
  120. void Drawable::setOriginWithOriginalSize (Point<float> originWithinParent)
  121. {
  122. setTransform (AffineTransform::translation (originWithinParent.x, originWithinParent.y));
  123. }
  124. void Drawable::setTransformToFit (const Rectangle<float>& area, RectanglePlacement placement)
  125. {
  126. if (! area.isEmpty())
  127. setTransform (placement.getTransformToFit (getDrawableBounds(), area));
  128. }
  129. //==============================================================================
  130. Drawable* Drawable::createFromImageData (const void* data, const size_t numBytes)
  131. {
  132. Drawable* result = nullptr;
  133. auto image = ImageFileFormat::loadFrom (data, numBytes);
  134. if (image.isValid())
  135. {
  136. auto* di = new DrawableImage();
  137. di->setImage (image);
  138. result = di;
  139. }
  140. else
  141. {
  142. auto asString = String::createStringFromData (data, (int) numBytes);
  143. XmlDocument doc (asString);
  144. ScopedPointer<XmlElement> outer (doc.getDocumentElement (true));
  145. if (outer != nullptr && outer->hasTagName ("svg"))
  146. {
  147. ScopedPointer<XmlElement> svg (doc.getDocumentElement());
  148. if (svg != nullptr)
  149. result = Drawable::createFromSVG (*svg);
  150. }
  151. }
  152. return result;
  153. }
  154. Drawable* Drawable::createFromImageDataStream (InputStream& dataSource)
  155. {
  156. MemoryOutputStream mo;
  157. mo << dataSource;
  158. return createFromImageData (mo.getData(), mo.getDataSize());
  159. }
  160. Drawable* Drawable::createFromImageFile (const File& file)
  161. {
  162. FileInputStream fin (file);
  163. return fin.openedOk() ? createFromImageDataStream (fin) : nullptr;
  164. }
  165. //==============================================================================
  166. template <class DrawableClass>
  167. struct DrawableTypeHandler : public ComponentBuilder::TypeHandler
  168. {
  169. DrawableTypeHandler() : ComponentBuilder::TypeHandler (DrawableClass::valueTreeType)
  170. {
  171. }
  172. Component* addNewComponentFromState (const ValueTree& state, Component* parent)
  173. {
  174. auto* d = new DrawableClass();
  175. if (parent != nullptr)
  176. parent->addAndMakeVisible (d);
  177. updateComponentFromState (d, state);
  178. return d;
  179. }
  180. void updateComponentFromState (Component* component, const ValueTree& state)
  181. {
  182. if (auto* d = dynamic_cast<DrawableClass*> (component))
  183. d->refreshFromValueTree (state, *this->getBuilder());
  184. else
  185. jassertfalse;
  186. }
  187. };
  188. void Drawable::registerDrawableTypeHandlers (ComponentBuilder& builder)
  189. {
  190. builder.registerTypeHandler (new DrawableTypeHandler<DrawablePath>());
  191. builder.registerTypeHandler (new DrawableTypeHandler<DrawableComposite>());
  192. builder.registerTypeHandler (new DrawableTypeHandler<DrawableRectangle>());
  193. builder.registerTypeHandler (new DrawableTypeHandler<DrawableImage>());
  194. builder.registerTypeHandler (new DrawableTypeHandler<DrawableText>());
  195. }
  196. Drawable* Drawable::createFromValueTree (const ValueTree& tree, ComponentBuilder::ImageProvider* imageProvider)
  197. {
  198. ComponentBuilder builder (tree);
  199. builder.setImageProvider (imageProvider);
  200. registerDrawableTypeHandlers (builder);
  201. ScopedPointer<Component> comp (builder.createComponent());
  202. auto* d = dynamic_cast<Drawable*> (static_cast<Component*> (comp));
  203. if (d != nullptr)
  204. comp.release();
  205. return d;
  206. }
  207. //==============================================================================
  208. Drawable::ValueTreeWrapperBase::ValueTreeWrapperBase (const ValueTree& s) : state (s)
  209. {
  210. }
  211. String Drawable::ValueTreeWrapperBase::getID() const
  212. {
  213. return state [ComponentBuilder::idProperty];
  214. }
  215. void Drawable::ValueTreeWrapperBase::setID (const String& newID)
  216. {
  217. if (newID.isEmpty())
  218. state.removeProperty (ComponentBuilder::idProperty, nullptr);
  219. else
  220. state.setProperty (ComponentBuilder::idProperty, newID, nullptr);
  221. }