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.

252 lines
7.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. Drawable::Drawable()
  18. {
  19. setInterceptsMouseClicks (false, false);
  20. setPaintingIsUnclipped (true);
  21. }
  22. Drawable::Drawable (const Drawable& other)
  23. : Component (other.getName())
  24. {
  25. setComponentID (other.getComponentID());
  26. }
  27. Drawable::~Drawable()
  28. {
  29. }
  30. //==============================================================================
  31. void Drawable::draw (Graphics& g, float opacity, const AffineTransform& transform) const
  32. {
  33. const_cast <Drawable*> (this)->nonConstDraw (g, opacity, transform);
  34. }
  35. void Drawable::nonConstDraw (Graphics& g, float opacity, const AffineTransform& transform)
  36. {
  37. Graphics::ScopedSaveState ss (g);
  38. g.addTransform (AffineTransform::translation ((float) -(originRelativeToComponent.x),
  39. (float) -(originRelativeToComponent.y))
  40. .followedBy (getTransform())
  41. .followedBy (transform));
  42. if (! g.isClipEmpty())
  43. {
  44. if (opacity < 1.0f)
  45. {
  46. g.beginTransparencyLayer (opacity);
  47. paintEntireComponent (g, true);
  48. g.endTransparencyLayer();
  49. }
  50. else
  51. {
  52. paintEntireComponent (g, true);
  53. }
  54. }
  55. }
  56. void Drawable::drawAt (Graphics& g, float x, float y, float opacity) const
  57. {
  58. draw (g, opacity, AffineTransform::translation (x, y));
  59. }
  60. void Drawable::drawWithin (Graphics& g, const Rectangle<float>& destArea,
  61. RectanglePlacement placement, float opacity) const
  62. {
  63. draw (g, opacity, placement.getTransformToFit (getDrawableBounds(), destArea));
  64. }
  65. //==============================================================================
  66. DrawableComposite* Drawable::getParent() const
  67. {
  68. return dynamic_cast <DrawableComposite*> (getParentComponent());
  69. }
  70. void Drawable::transformContextToCorrectOrigin (Graphics& g)
  71. {
  72. g.setOrigin (originRelativeToComponent);
  73. }
  74. void Drawable::parentHierarchyChanged()
  75. {
  76. setBoundsToEnclose (getDrawableBounds());
  77. }
  78. void Drawable::setBoundsToEnclose (const Rectangle<float>& area)
  79. {
  80. Drawable* const parent = getParent();
  81. Point<int> parentOrigin;
  82. if (parent != nullptr)
  83. parentOrigin = parent->originRelativeToComponent;
  84. const Rectangle<int> newBounds (area.getSmallestIntegerContainer() + parentOrigin);
  85. originRelativeToComponent = parentOrigin - newBounds.getPosition();
  86. setBounds (newBounds);
  87. }
  88. //==============================================================================
  89. bool Drawable::replaceColour (Colour original, Colour replacement)
  90. {
  91. bool changed = false;
  92. for (int i = getNumChildComponents(); --i >= 0;)
  93. if (Drawable* d = dynamic_cast<Drawable*> (getChildComponent(i)))
  94. changed = d->replaceColour (original, replacement) || changed;
  95. return changed;
  96. }
  97. //==============================================================================
  98. void Drawable::setOriginWithOriginalSize (Point<float> originWithinParent)
  99. {
  100. setTransform (AffineTransform::translation (originWithinParent.x, originWithinParent.y));
  101. }
  102. void Drawable::setTransformToFit (const Rectangle<float>& area, RectanglePlacement placement)
  103. {
  104. if (! area.isEmpty())
  105. setTransform (placement.getTransformToFit (getDrawableBounds(), area));
  106. }
  107. //==============================================================================
  108. Drawable* Drawable::createFromImageData (const void* data, const size_t numBytes)
  109. {
  110. Drawable* result = nullptr;
  111. Image image (ImageFileFormat::loadFrom (data, numBytes));
  112. if (image.isValid())
  113. {
  114. DrawableImage* const di = new DrawableImage();
  115. di->setImage (image);
  116. result = di;
  117. }
  118. else
  119. {
  120. const String asString (String::createStringFromData (data, (int) numBytes));
  121. XmlDocument doc (asString);
  122. ScopedPointer <XmlElement> outer (doc.getDocumentElement (true));
  123. if (outer != nullptr && outer->hasTagName ("svg"))
  124. {
  125. ScopedPointer <XmlElement> svg (doc.getDocumentElement());
  126. if (svg != nullptr)
  127. result = Drawable::createFromSVG (*svg);
  128. }
  129. }
  130. return result;
  131. }
  132. Drawable* Drawable::createFromImageDataStream (InputStream& dataSource)
  133. {
  134. MemoryOutputStream mo;
  135. mo << dataSource;
  136. return createFromImageData (mo.getData(), mo.getDataSize());
  137. }
  138. Drawable* Drawable::createFromImageFile (const File& file)
  139. {
  140. FileInputStream fin (file);
  141. return fin.openedOk() ? createFromImageDataStream (fin) : nullptr;
  142. }
  143. //==============================================================================
  144. template <class DrawableClass>
  145. class DrawableTypeHandler : public ComponentBuilder::TypeHandler
  146. {
  147. public:
  148. DrawableTypeHandler()
  149. : ComponentBuilder::TypeHandler (DrawableClass::valueTreeType)
  150. {
  151. }
  152. Component* addNewComponentFromState (const ValueTree& state, Component* parent)
  153. {
  154. DrawableClass* const d = new DrawableClass();
  155. if (parent != nullptr)
  156. parent->addAndMakeVisible (d);
  157. updateComponentFromState (d, state);
  158. return d;
  159. }
  160. void updateComponentFromState (Component* component, const ValueTree& state)
  161. {
  162. DrawableClass* const d = dynamic_cast <DrawableClass*> (component);
  163. jassert (d != nullptr);
  164. d->refreshFromValueTree (state, *this->getBuilder());
  165. }
  166. };
  167. void Drawable::registerDrawableTypeHandlers (ComponentBuilder& builder)
  168. {
  169. builder.registerTypeHandler (new DrawableTypeHandler <DrawablePath>());
  170. builder.registerTypeHandler (new DrawableTypeHandler <DrawableComposite>());
  171. builder.registerTypeHandler (new DrawableTypeHandler <DrawableRectangle>());
  172. builder.registerTypeHandler (new DrawableTypeHandler <DrawableImage>());
  173. builder.registerTypeHandler (new DrawableTypeHandler <DrawableText>());
  174. }
  175. Drawable* Drawable::createFromValueTree (const ValueTree& tree, ComponentBuilder::ImageProvider* imageProvider)
  176. {
  177. ComponentBuilder builder (tree);
  178. builder.setImageProvider (imageProvider);
  179. registerDrawableTypeHandlers (builder);
  180. ScopedPointer<Component> comp (builder.createComponent());
  181. Drawable* const d = dynamic_cast<Drawable*> (static_cast <Component*> (comp));
  182. if (d != nullptr)
  183. comp.release();
  184. return d;
  185. }
  186. //==============================================================================
  187. Drawable::ValueTreeWrapperBase::ValueTreeWrapperBase (const ValueTree& state_)
  188. : state (state_)
  189. {
  190. }
  191. String Drawable::ValueTreeWrapperBase::getID() const
  192. {
  193. return state [ComponentBuilder::idProperty];
  194. }
  195. void Drawable::ValueTreeWrapperBase::setID (const String& newID)
  196. {
  197. if (newID.isEmpty())
  198. state.removeProperty (ComponentBuilder::idProperty, nullptr);
  199. else
  200. state.setProperty (ComponentBuilder::idProperty, newID, nullptr);
  201. }