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.

323 lines
10KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 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. #ifndef __JUCER_DRAWABLEOBJECTCOMPONENT_JUCEHEADER__
  19. #define __JUCER_DRAWABLEOBJECTCOMPONENT_JUCEHEADER__
  20. #include "jucer_DrawableEditor.h"
  21. //==============================================================================
  22. class DrawableObjectComponent : public Component,
  23. public ValueTree::Listener,
  24. public ChangeListener
  25. {
  26. public:
  27. DrawableObjectComponent (const ValueTree& drawableNode_,
  28. DrawableEditor& editor_,
  29. Drawable* drawable_)
  30. : drawable (drawable_),
  31. drawableNode (drawableNode_),
  32. editor (editor_)
  33. {
  34. setVisible (true);
  35. nodeHashCode = DrawableEditor::getHashForNode (drawableNode);
  36. drawableNode.addListener (this);
  37. editor.selectedItems.addChangeListener (this);
  38. }
  39. ~DrawableObjectComponent()
  40. {
  41. deleteAllChildren();
  42. editor.selectedItems.removeChangeListener (this);
  43. drawableNode.removeListener (this);
  44. drawable = 0;
  45. }
  46. static DrawableObjectComponent* create (const ValueTree& node, DrawableEditor& editor, Drawable* drawable_);
  47. //==============================================================================
  48. void paint (Graphics& g)
  49. {
  50. //g.setColour (Colours::pink.withAlpha (0.2f));
  51. //g.fillRect (0, 0, getWidth(), getHeight());
  52. if (isSelected())
  53. {
  54. g.setColour (Colours::red);
  55. g.drawRect (0, 0, getWidth(), getHeight(), 2);
  56. }
  57. const Point<int> offset (getDrawableOriginRelativeToTopLeft());
  58. g.setOrigin (offset.getX(), offset.getY());
  59. drawable->draw (g, 1.0f, transform);
  60. }
  61. const Point<int> getDrawableOriginRelativeToTopLeft() const
  62. {
  63. return drawableOriginRelativeToParentTopLeft - getPosition();
  64. }
  65. void findLassoItemsInArea (Array <int64>& itemsFound, Rectangle<int> r) const
  66. {
  67. if (getBounds().intersects (r))
  68. itemsFound.add (nodeHashCode);
  69. r.translate (-getX(), -getY());
  70. for (int i = getNumChildComponents(); --i >= 0;)
  71. {
  72. DrawableObjectComponent* d = dynamic_cast <DrawableObjectComponent*> (getChildComponent(i));
  73. if (d != 0)
  74. d->findLassoItemsInArea (itemsFound, r);
  75. }
  76. }
  77. bool isSelected() const
  78. {
  79. return editor.selectedItems.isSelected (nodeHashCode);
  80. }
  81. //==============================================================================
  82. void valueTreePropertyChanged (ValueTree& tree, const var::identifier& property)
  83. {
  84. if (tree == drawableNode)
  85. {
  86. editor.getDocument().changed();
  87. reloadFromValueTree();
  88. repaint();
  89. }
  90. }
  91. void valueTreeChildrenChanged (ValueTree& tree)
  92. {
  93. if (tree == drawableNode)
  94. {
  95. editor.getDocument().changed();
  96. reloadFromValueTree();
  97. repaint();
  98. }
  99. }
  100. void valueTreeParentChanged (ValueTree& tree)
  101. {
  102. editor.getDocument().changed();
  103. reloadFromValueTree();
  104. repaint();
  105. }
  106. void changeListenerCallback (void*)
  107. {
  108. repaint();
  109. }
  110. //==============================================================================
  111. virtual void reloadFromValueTree() = 0;
  112. void commitModifiedPath()
  113. {
  114. drawableNode = drawable->createValueTree();
  115. }
  116. //==============================================================================
  117. AffineTransform transform;
  118. ScopedPointer <Drawable> drawable;
  119. ValueTree drawableNode;
  120. int64 nodeHashCode;
  121. DrawableEditor& editor;
  122. Point<int> drawableOriginRelativeToParentTopLeft;
  123. };
  124. //==============================================================================
  125. class PathDrawableComponent : public DrawableObjectComponent
  126. {
  127. public:
  128. PathDrawableComponent (const ValueTree& drawableNode_,
  129. DrawableEditor& editor_,
  130. DrawablePath* drawable_)
  131. : DrawableObjectComponent (drawableNode_, editor_, drawable_)
  132. {
  133. }
  134. ~PathDrawableComponent()
  135. {
  136. }
  137. // Relative to the drawable's origin, not the parent component or any other comp.
  138. const Rectangle<int> getBoundsRectangle()
  139. {
  140. if (drawable == 0)
  141. reloadFromValueTree();
  142. return drawable->getBounds().getSmallestIntegerContainer().expanded (2, 2);
  143. }
  144. bool hitTest (int x, int y)
  145. {
  146. const Point<int> offset (getDrawableOriginRelativeToTopLeft());
  147. return drawable->hitTest ((float) x - offset.getX(),
  148. (float) y - offset.getY());
  149. }
  150. void mouseDown (const MouseEvent& e)
  151. {
  152. mouseDownSelectResult = editor.selectedItems.addToSelectionOnMouseDown (nodeHashCode, e.mods);
  153. pathBoundsOnMouseDown = getPath()->getPath().getBounds();
  154. }
  155. void mouseDrag (const MouseEvent& e)
  156. {
  157. }
  158. void mouseUp (const MouseEvent& e)
  159. {
  160. editor.selectedItems.addToSelectionOnMouseUp (nodeHashCode, e.mods,
  161. ! e.mouseWasClicked(),
  162. mouseDownSelectResult);
  163. }
  164. void reloadFromValueTree()
  165. {
  166. drawable = Drawable::createFromValueTree (drawableNode);
  167. jassert (dynamic_cast <DrawablePath*> ((Drawable*) drawable) != 0);
  168. setBounds (getBoundsRectangle().translated (drawableOriginRelativeToParentTopLeft.getX(),
  169. drawableOriginRelativeToParentTopLeft.getY()));
  170. }
  171. private:
  172. bool mouseDownSelectResult;
  173. Rectangle<float> pathBoundsOnMouseDown;
  174. DrawablePath* getPath() const
  175. {
  176. return dynamic_cast <DrawablePath*> ((Drawable*) drawable);
  177. }
  178. };
  179. //==============================================================================
  180. class CompositeDrawableComponent : public DrawableObjectComponent
  181. {
  182. public:
  183. CompositeDrawableComponent (const ValueTree& drawableNode_,
  184. DrawableEditor& editor_,
  185. DrawableComposite* drawable_)
  186. : DrawableObjectComponent (drawableNode_, editor_, drawable_)
  187. {
  188. }
  189. ~CompositeDrawableComponent()
  190. {
  191. }
  192. void reloadFromValueTree()
  193. {
  194. drawable = Drawable::createFromValueTree (drawableNode);
  195. DrawableComposite* dc = dynamic_cast <DrawableComposite*> ((Drawable*) drawable);
  196. jassert (dc != 0);
  197. deleteAllChildren();
  198. Rectangle<int> childBounds;
  199. int i;
  200. for (i = 0; i < dc->getNumDrawables(); ++i)
  201. {
  202. Drawable* d = dc->getDrawable (i);
  203. jassert (d != 0);
  204. DrawableObjectComponent* c = DrawableObjectComponent::create (drawableNode.getChild(i), editor, d);
  205. if (c != 0)
  206. {
  207. addChildComponent (c);
  208. const AffineTransform* t = dc->getDrawableTransform (i);
  209. if (t != 0)
  210. c->transform = *t;
  211. c->drawableOriginRelativeToParentTopLeft = drawableOriginRelativeToParentTopLeft;
  212. c->reloadFromValueTree();
  213. if (childBounds.isEmpty())
  214. childBounds = c->getBounds();
  215. else
  216. childBounds = childBounds.getUnion (c->getBounds());
  217. }
  218. }
  219. for (i = dc->getNumDrawables(); --i >= 0;)
  220. dc->removeDrawable (i, false);
  221. setBounds (childBounds);
  222. for (i = getNumChildComponents(); --i >= 0;)
  223. {
  224. DrawableObjectComponent* dc = dynamic_cast <DrawableObjectComponent*> (getChildComponent (i));
  225. if (dc != 0)
  226. {
  227. dc->setTopLeftPosition (dc->getX() - getX(), dc->getY() - getY());
  228. dc->drawableOriginRelativeToParentTopLeft = drawableOriginRelativeToParentTopLeft - getPosition();
  229. }
  230. }
  231. }
  232. };
  233. //==============================================================================
  234. DrawableObjectComponent* DrawableObjectComponent::create (const ValueTree& node, DrawableEditor& editor, Drawable* drawable_)
  235. {
  236. ScopedPointer<Drawable> drawable (drawable_);
  237. if (drawable == 0)
  238. drawable = Drawable::createFromValueTree (node);
  239. DrawablePath* p = dynamic_cast <DrawablePath*> ((Drawable*) drawable);
  240. if (p != 0)
  241. {
  242. drawable.release();
  243. return new PathDrawableComponent (node, editor, p);
  244. }
  245. DrawableComposite* dc = dynamic_cast <DrawableComposite*> ((Drawable*) drawable);
  246. if (dc != 0)
  247. {
  248. drawable.release();
  249. return new CompositeDrawableComponent (node, editor, dc);
  250. }
  251. jassertfalse
  252. return 0;
  253. }
  254. #endif // __JUCER_DRAWABLEOBJECTCOMPONENT_JUCEHEADER__