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.

290 lines
9.4KB

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