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.

303 lines
9.5KB

  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. DrawableImage::DrawableImage()
  22. : opacity (1.0f),
  23. overlayColour (0x00000000)
  24. {
  25. bounds.topRight = RelativePoint (Point<float> (1.0f, 0.0f));
  26. bounds.bottomLeft = RelativePoint (Point<float> (0.0f, 1.0f));
  27. }
  28. DrawableImage::DrawableImage (const DrawableImage& other)
  29. : Drawable (other),
  30. image (other.image),
  31. opacity (other.opacity),
  32. overlayColour (other.overlayColour),
  33. bounds (other.bounds)
  34. {
  35. setBounds (other.getBounds());
  36. }
  37. DrawableImage::~DrawableImage()
  38. {
  39. }
  40. //==============================================================================
  41. void DrawableImage::setImage (const Image& imageToUse)
  42. {
  43. image = imageToUse;
  44. setBounds (imageToUse.getBounds());
  45. bounds.topLeft = RelativePoint (Point<float> (0.0f, 0.0f));
  46. bounds.topRight = RelativePoint (Point<float> ((float) image.getWidth(), 0.0f));
  47. bounds.bottomLeft = RelativePoint (Point<float> (0.0f, (float) image.getHeight()));
  48. recalculateCoordinates (nullptr);
  49. repaint();
  50. }
  51. void DrawableImage::setOpacity (const float newOpacity)
  52. {
  53. opacity = newOpacity;
  54. }
  55. void DrawableImage::setOverlayColour (Colour newOverlayColour)
  56. {
  57. overlayColour = newOverlayColour;
  58. }
  59. void DrawableImage::setBoundingBox (const RelativeParallelogram& newBounds)
  60. {
  61. if (bounds != newBounds)
  62. {
  63. bounds = newBounds;
  64. if (bounds.isDynamic())
  65. {
  66. Drawable::Positioner<DrawableImage>* const p = new Drawable::Positioner<DrawableImage> (*this);
  67. setPositioner (p);
  68. p->apply();
  69. }
  70. else
  71. {
  72. setPositioner (nullptr);
  73. recalculateCoordinates (nullptr);
  74. }
  75. }
  76. }
  77. //==============================================================================
  78. bool DrawableImage::registerCoordinates (RelativeCoordinatePositionerBase& pos)
  79. {
  80. bool ok = pos.addPoint (bounds.topLeft);
  81. ok = pos.addPoint (bounds.topRight) && ok;
  82. return pos.addPoint (bounds.bottomLeft) && ok;
  83. }
  84. void DrawableImage::recalculateCoordinates (Expression::Scope* scope)
  85. {
  86. if (image.isValid())
  87. {
  88. Point<float> resolved[3];
  89. bounds.resolveThreePoints (resolved, scope);
  90. const Point<float> tr (resolved[0] + (resolved[1] - resolved[0]) / (float) image.getWidth());
  91. const Point<float> bl (resolved[0] + (resolved[2] - resolved[0]) / (float) image.getHeight());
  92. AffineTransform t (AffineTransform::fromTargetPoints (resolved[0].x, resolved[0].y,
  93. tr.x, tr.y,
  94. bl.x, bl.y));
  95. if (t.isSingularity())
  96. t = AffineTransform();
  97. setTransform (t);
  98. }
  99. }
  100. //==============================================================================
  101. void DrawableImage::paint (Graphics& g)
  102. {
  103. if (image.isValid())
  104. {
  105. if (opacity > 0.0f && ! overlayColour.isOpaque())
  106. {
  107. g.setOpacity (opacity);
  108. g.drawImageAt (image, 0, 0, false);
  109. }
  110. if (! overlayColour.isTransparent())
  111. {
  112. g.setColour (overlayColour.withMultipliedAlpha (opacity));
  113. g.drawImageAt (image, 0, 0, true);
  114. }
  115. }
  116. }
  117. Rectangle<float> DrawableImage::getDrawableBounds() const
  118. {
  119. return image.getBounds().toFloat();
  120. }
  121. bool DrawableImage::hitTest (int x, int y)
  122. {
  123. return Drawable::hitTest (x, y) && image.isValid() && image.getPixelAt (x, y).getAlpha() >= 127;
  124. }
  125. Drawable* DrawableImage::createCopy() const
  126. {
  127. return new DrawableImage (*this);
  128. }
  129. //==============================================================================
  130. const Identifier DrawableImage::valueTreeType ("Image");
  131. const Identifier DrawableImage::ValueTreeWrapper::opacity ("opacity");
  132. const Identifier DrawableImage::ValueTreeWrapper::overlay ("overlay");
  133. const Identifier DrawableImage::ValueTreeWrapper::image ("image");
  134. const Identifier DrawableImage::ValueTreeWrapper::topLeft ("topLeft");
  135. const Identifier DrawableImage::ValueTreeWrapper::topRight ("topRight");
  136. const Identifier DrawableImage::ValueTreeWrapper::bottomLeft ("bottomLeft");
  137. //==============================================================================
  138. DrawableImage::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_)
  139. : ValueTreeWrapperBase (state_)
  140. {
  141. jassert (state.hasType (valueTreeType));
  142. }
  143. var DrawableImage::ValueTreeWrapper::getImageIdentifier() const
  144. {
  145. return state [image];
  146. }
  147. Value DrawableImage::ValueTreeWrapper::getImageIdentifierValue (UndoManager* undoManager)
  148. {
  149. return state.getPropertyAsValue (image, undoManager);
  150. }
  151. void DrawableImage::ValueTreeWrapper::setImageIdentifier (const var& newIdentifier, UndoManager* undoManager)
  152. {
  153. state.setProperty (image, newIdentifier, undoManager);
  154. }
  155. float DrawableImage::ValueTreeWrapper::getOpacity() const
  156. {
  157. return (float) state.getProperty (opacity, 1.0);
  158. }
  159. Value DrawableImage::ValueTreeWrapper::getOpacityValue (UndoManager* undoManager)
  160. {
  161. if (! state.hasProperty (opacity))
  162. state.setProperty (opacity, 1.0, undoManager);
  163. return state.getPropertyAsValue (opacity, undoManager);
  164. }
  165. void DrawableImage::ValueTreeWrapper::setOpacity (float newOpacity, UndoManager* undoManager)
  166. {
  167. state.setProperty (opacity, newOpacity, undoManager);
  168. }
  169. Colour DrawableImage::ValueTreeWrapper::getOverlayColour() const
  170. {
  171. return Colour::fromString (state [overlay].toString());
  172. }
  173. void DrawableImage::ValueTreeWrapper::setOverlayColour (Colour newColour, UndoManager* undoManager)
  174. {
  175. if (newColour.isTransparent())
  176. state.removeProperty (overlay, undoManager);
  177. else
  178. state.setProperty (overlay, String::toHexString ((int) newColour.getARGB()), undoManager);
  179. }
  180. Value DrawableImage::ValueTreeWrapper::getOverlayColourValue (UndoManager* undoManager)
  181. {
  182. return state.getPropertyAsValue (overlay, undoManager);
  183. }
  184. RelativeParallelogram DrawableImage::ValueTreeWrapper::getBoundingBox() const
  185. {
  186. return RelativeParallelogram (state.getProperty (topLeft, "0, 0"),
  187. state.getProperty (topRight, "100, 0"),
  188. state.getProperty (bottomLeft, "0, 100"));
  189. }
  190. void DrawableImage::ValueTreeWrapper::setBoundingBox (const RelativeParallelogram& newBounds, UndoManager* undoManager)
  191. {
  192. state.setProperty (topLeft, newBounds.topLeft.toString(), undoManager);
  193. state.setProperty (topRight, newBounds.topRight.toString(), undoManager);
  194. state.setProperty (bottomLeft, newBounds.bottomLeft.toString(), undoManager);
  195. }
  196. //==============================================================================
  197. void DrawableImage::refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder)
  198. {
  199. const ValueTreeWrapper controller (tree);
  200. setComponentID (controller.getID());
  201. const float newOpacity = controller.getOpacity();
  202. const Colour newOverlayColour (controller.getOverlayColour());
  203. Image newImage;
  204. const var imageIdentifier (controller.getImageIdentifier());
  205. jassert (builder.getImageProvider() != 0 || imageIdentifier.isVoid()); // if you're using images, you need to provide something that can load and save them!
  206. if (builder.getImageProvider() != nullptr)
  207. newImage = builder.getImageProvider()->getImageForIdentifier (imageIdentifier);
  208. const RelativeParallelogram newBounds (controller.getBoundingBox());
  209. if (bounds != newBounds || newOpacity != opacity
  210. || overlayColour != newOverlayColour || image != newImage)
  211. {
  212. repaint();
  213. opacity = newOpacity;
  214. overlayColour = newOverlayColour;
  215. if (image != newImage)
  216. setImage (newImage);
  217. setBoundingBox (newBounds);
  218. }
  219. }
  220. ValueTree DrawableImage::createValueTree (ComponentBuilder::ImageProvider* imageProvider) const
  221. {
  222. ValueTree tree (valueTreeType);
  223. ValueTreeWrapper v (tree);
  224. v.setID (getComponentID());
  225. v.setOpacity (opacity, nullptr);
  226. v.setOverlayColour (overlayColour, nullptr);
  227. v.setBoundingBox (bounds, nullptr);
  228. if (image.isValid())
  229. {
  230. jassert (imageProvider != nullptr); // if you're using images, you need to provide something that can load and save them!
  231. if (imageProvider != nullptr)
  232. v.setImageIdentifier (imageProvider->getIdentifierForImage (image), nullptr);
  233. }
  234. return tree;
  235. }
  236. Path DrawableImage::getOutlineAsPath() const
  237. {
  238. return {}; // not applicable for images
  239. }
  240. } // namespace juce