juce_DrawableImage.cpp 9.4 KB

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