The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

296 lines
9.7KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. BEGIN_JUCE_NAMESPACE
  19. //==============================================================================
  20. DrawableImage::DrawableImage()
  21. : opacity (1.0f),
  22. overlayColour (0x00000000)
  23. {
  24. bounds.topRight = RelativePoint (Point<float> (1.0f, 0.0f));
  25. bounds.bottomLeft = RelativePoint (Point<float> (0.0f, 1.0f));
  26. }
  27. DrawableImage::DrawableImage (const DrawableImage& other)
  28. : image (other.image),
  29. opacity (other.opacity),
  30. overlayColour (other.overlayColour),
  31. bounds (other.bounds)
  32. {
  33. }
  34. DrawableImage::~DrawableImage()
  35. {
  36. }
  37. //==============================================================================
  38. void DrawableImage::setImage (const Image& imageToUse)
  39. {
  40. image = imageToUse;
  41. setBounds (imageToUse.getBounds());
  42. bounds.topLeft = RelativePoint (Point<float> (0.0f, 0.0f));
  43. bounds.topRight = RelativePoint (Point<float> ((float) image.getWidth(), 0.0f));
  44. bounds.bottomLeft = RelativePoint (Point<float> (0.0f, (float) image.getHeight()));
  45. recalculateCoordinates (nullptr);
  46. repaint();
  47. }
  48. void DrawableImage::setOpacity (const float newOpacity)
  49. {
  50. opacity = newOpacity;
  51. }
  52. void DrawableImage::setOverlayColour (const Colour& newOverlayColour)
  53. {
  54. overlayColour = newOverlayColour;
  55. }
  56. void DrawableImage::setBoundingBox (const RelativeParallelogram& newBounds)
  57. {
  58. if (bounds != newBounds)
  59. {
  60. bounds = newBounds;
  61. if (bounds.isDynamic())
  62. {
  63. Drawable::Positioner<DrawableImage>* const p = new Drawable::Positioner<DrawableImage> (*this);
  64. setPositioner (p);
  65. p->apply();
  66. }
  67. else
  68. {
  69. setPositioner (nullptr);
  70. recalculateCoordinates (nullptr);
  71. }
  72. }
  73. }
  74. //==============================================================================
  75. bool DrawableImage::registerCoordinates (RelativeCoordinatePositionerBase& pos)
  76. {
  77. bool ok = pos.addPoint (bounds.topLeft);
  78. ok = pos.addPoint (bounds.topRight) && ok;
  79. return pos.addPoint (bounds.bottomLeft) && ok;
  80. }
  81. void DrawableImage::recalculateCoordinates (Expression::Scope* scope)
  82. {
  83. if (image.isValid())
  84. {
  85. Point<float> resolved[3];
  86. bounds.resolveThreePoints (resolved, scope);
  87. const Point<float> tr (resolved[0] + (resolved[1] - resolved[0]) / (float) image.getWidth());
  88. const Point<float> bl (resolved[0] + (resolved[2] - resolved[0]) / (float) image.getHeight());
  89. AffineTransform t (AffineTransform::fromTargetPoints (resolved[0].getX(), resolved[0].getY(),
  90. tr.getX(), tr.getY(),
  91. bl.getX(), bl.getY()));
  92. if (t.isSingularity())
  93. t = AffineTransform::identity;
  94. setTransform (t);
  95. }
  96. }
  97. //==============================================================================
  98. void DrawableImage::paint (Graphics& g)
  99. {
  100. if (image.isValid())
  101. {
  102. if (opacity > 0.0f && ! overlayColour.isOpaque())
  103. {
  104. g.setOpacity (opacity);
  105. g.drawImageAt (image, 0, 0, false);
  106. }
  107. if (! overlayColour.isTransparent())
  108. {
  109. g.setColour (overlayColour.withMultipliedAlpha (opacity));
  110. g.drawImageAt (image, 0, 0, true);
  111. }
  112. }
  113. }
  114. Rectangle<float> DrawableImage::getDrawableBounds() const
  115. {
  116. return image.getBounds().toFloat();
  117. }
  118. bool DrawableImage::hitTest (int x, int y)
  119. {
  120. return Drawable::hitTest (x, y) && image.isValid() && image.getPixelAt (x, y).getAlpha() >= 127;
  121. }
  122. Drawable* DrawableImage::createCopy() const
  123. {
  124. return new DrawableImage (*this);
  125. }
  126. //==============================================================================
  127. const Identifier DrawableImage::valueTreeType ("Image");
  128. const Identifier DrawableImage::ValueTreeWrapper::opacity ("opacity");
  129. const Identifier DrawableImage::ValueTreeWrapper::overlay ("overlay");
  130. const Identifier DrawableImage::ValueTreeWrapper::image ("image");
  131. const Identifier DrawableImage::ValueTreeWrapper::topLeft ("topLeft");
  132. const Identifier DrawableImage::ValueTreeWrapper::topRight ("topRight");
  133. const Identifier DrawableImage::ValueTreeWrapper::bottomLeft ("bottomLeft");
  134. //==============================================================================
  135. DrawableImage::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_)
  136. : ValueTreeWrapperBase (state_)
  137. {
  138. jassert (state.hasType (valueTreeType));
  139. }
  140. var DrawableImage::ValueTreeWrapper::getImageIdentifier() const
  141. {
  142. return state [image];
  143. }
  144. Value DrawableImage::ValueTreeWrapper::getImageIdentifierValue (UndoManager* undoManager)
  145. {
  146. return state.getPropertyAsValue (image, undoManager);
  147. }
  148. void DrawableImage::ValueTreeWrapper::setImageIdentifier (const var& newIdentifier, UndoManager* undoManager)
  149. {
  150. state.setProperty (image, newIdentifier, undoManager);
  151. }
  152. float DrawableImage::ValueTreeWrapper::getOpacity() const
  153. {
  154. return (float) state.getProperty (opacity, 1.0);
  155. }
  156. Value DrawableImage::ValueTreeWrapper::getOpacityValue (UndoManager* undoManager)
  157. {
  158. if (! state.hasProperty (opacity))
  159. state.setProperty (opacity, 1.0, undoManager);
  160. return state.getPropertyAsValue (opacity, undoManager);
  161. }
  162. void DrawableImage::ValueTreeWrapper::setOpacity (float newOpacity, UndoManager* undoManager)
  163. {
  164. state.setProperty (opacity, newOpacity, undoManager);
  165. }
  166. const Colour DrawableImage::ValueTreeWrapper::getOverlayColour() const
  167. {
  168. return Colour ((uint32) state [overlay].toString().getHexValue32());
  169. }
  170. void DrawableImage::ValueTreeWrapper::setOverlayColour (const Colour& newColour, UndoManager* undoManager)
  171. {
  172. if (newColour.isTransparent())
  173. state.removeProperty (overlay, undoManager);
  174. else
  175. state.setProperty (overlay, String::toHexString ((int) newColour.getARGB()), undoManager);
  176. }
  177. Value DrawableImage::ValueTreeWrapper::getOverlayColourValue (UndoManager* undoManager)
  178. {
  179. return state.getPropertyAsValue (overlay, undoManager);
  180. }
  181. RelativeParallelogram DrawableImage::ValueTreeWrapper::getBoundingBox() const
  182. {
  183. return RelativeParallelogram (state.getProperty (topLeft, "0, 0"),
  184. state.getProperty (topRight, "100, 0"),
  185. state.getProperty (bottomLeft, "0, 100"));
  186. }
  187. void DrawableImage::ValueTreeWrapper::setBoundingBox (const RelativeParallelogram& newBounds, UndoManager* undoManager)
  188. {
  189. state.setProperty (topLeft, newBounds.topLeft.toString(), undoManager);
  190. state.setProperty (topRight, newBounds.topRight.toString(), undoManager);
  191. state.setProperty (bottomLeft, newBounds.bottomLeft.toString(), undoManager);
  192. }
  193. //==============================================================================
  194. void DrawableImage::refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder)
  195. {
  196. const ValueTreeWrapper controller (tree);
  197. setComponentID (controller.getID());
  198. const float newOpacity = controller.getOpacity();
  199. const Colour newOverlayColour (controller.getOverlayColour());
  200. Image newImage;
  201. const var imageIdentifier (controller.getImageIdentifier());
  202. jassert (builder.getImageProvider() != 0 || imageIdentifier.isVoid()); // if you're using images, you need to provide something that can load and save them!
  203. if (builder.getImageProvider() != nullptr)
  204. newImage = builder.getImageProvider()->getImageForIdentifier (imageIdentifier);
  205. const RelativeParallelogram newBounds (controller.getBoundingBox());
  206. if (bounds != newBounds || newOpacity != opacity
  207. || overlayColour != newOverlayColour || image != newImage)
  208. {
  209. repaint();
  210. opacity = newOpacity;
  211. overlayColour = newOverlayColour;
  212. if (image != newImage)
  213. setImage (newImage);
  214. setBoundingBox (newBounds);
  215. }
  216. }
  217. ValueTree DrawableImage::createValueTree (ComponentBuilder::ImageProvider* imageProvider) const
  218. {
  219. ValueTree tree (valueTreeType);
  220. ValueTreeWrapper v (tree);
  221. v.setID (getComponentID());
  222. v.setOpacity (opacity, nullptr);
  223. v.setOverlayColour (overlayColour, nullptr);
  224. v.setBoundingBox (bounds, nullptr);
  225. if (image.isValid())
  226. {
  227. jassert (imageProvider != nullptr); // if you're using images, you need to provide something that can load and save them!
  228. if (imageProvider != nullptr)
  229. v.setImageIdentifier (imageProvider->getIdentifierForImage (image), nullptr);
  230. }
  231. return tree;
  232. }
  233. END_JUCE_NAMESPACE