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.

757 lines
25KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 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. #include "../../model/Drawable/jucer_DrawableTypeHandler.h"
  22. //==============================================================================
  23. class DrawableEditorCanvas : public EditorCanvasBase,
  24. public FileDragAndDropTarget,
  25. public Timer
  26. {
  27. public:
  28. //==============================================================================
  29. DrawableEditorCanvas (DrawableEditor& editor_)
  30. : editor (editor_)
  31. {
  32. initialise();
  33. getDocument().getRoot().addListener (this);
  34. }
  35. ~DrawableEditorCanvas()
  36. {
  37. getDocument().getRoot().removeListener (this);
  38. shutdown();
  39. }
  40. //==============================================================================
  41. UndoManager& getUndoManager() throw() { return *getDocument().getUndoManager(); }
  42. DrawableEditor& getEditor() throw() { return editor; }
  43. DrawableDocument& getDocument() throw() { return editor.getDocument(); }
  44. Component* createComponentHolder()
  45. {
  46. return new DrawableComponent (this);
  47. }
  48. void documentChanged()
  49. {
  50. DrawableDocument& doc = getDocument();
  51. if (drawable == 0)
  52. {
  53. Drawable* newDrawable = Drawable::createFromValueTree (doc.getRootDrawableNode().getState(), &doc);
  54. drawable = dynamic_cast <DrawableComposite*> (newDrawable);
  55. drawable->resetBoundingBoxToContentArea();
  56. jassert (drawable != 0);
  57. getComponentHolder()->repaint();
  58. }
  59. else
  60. {
  61. doc.getRootDrawableNode().resetBoundingBoxToContentArea (0);
  62. const Rectangle<float> damage (drawable->refreshFromValueTree (doc.getRootDrawableNode().getState(), &doc));
  63. getComponentHolder()->repaint (objectSpaceToScreenSpace (damage.getSmallestIntegerContainer()));
  64. }
  65. startTimer (500);
  66. }
  67. const Rectangle<int> getCanvasBounds()
  68. {
  69. return drawable->getBounds().getSmallestIntegerContainer();
  70. }
  71. void setCanvasBounds (const Rectangle<int>& newBounds) {}
  72. bool canResizeCanvas() const { return false; }
  73. //==============================================================================
  74. const ValueTree getObjectState (const String& objectId)
  75. {
  76. return getDocument().findDrawableState (objectId, false);
  77. }
  78. const SelectedItems::ItemType findObjectIdAt (const Point<int>& position)
  79. {
  80. if (drawable != 0)
  81. {
  82. for (int i = drawable->getNumDrawables(); --i >= 0;)
  83. {
  84. Drawable* d = drawable->getDrawable (i);
  85. if (d->hitTest ((float) position.getX(), (float) position.getY()))
  86. return d->getName();
  87. }
  88. }
  89. return String::empty;
  90. }
  91. void showPopupMenu (bool isClickOnSelectedObject)
  92. {
  93. PopupMenu m;
  94. if (isClickOnSelectedObject)
  95. {
  96. m.addCommandItem (commandManager, CommandIDs::toFront);
  97. m.addCommandItem (commandManager, CommandIDs::toBack);
  98. m.addSeparator();
  99. m.addCommandItem (commandManager, StandardApplicationCommandIDs::del);
  100. const int r = m.show();
  101. (void) r;
  102. }
  103. else
  104. {
  105. editor.showNewShapeMenu (0);
  106. }
  107. }
  108. void objectDoubleClicked (const MouseEvent& e, const ValueTree& state)
  109. {
  110. if (state.hasType (DrawablePath::valueTreeType)
  111. || state.hasType (DrawableImage::valueTreeType)
  112. || state.hasType (DrawableText::valueTreeType)
  113. || state.hasType (DrawableComposite::valueTreeType))
  114. {
  115. enableControlPointMode (state);
  116. }
  117. else if (state.hasType (DrawableComposite::valueTreeType))
  118. {
  119. // xxx
  120. }
  121. }
  122. bool hasSizeGuides() const { return false; }
  123. void getObjectPositionDependencies (const ValueTree& state, Array<ValueTree>& deps)
  124. {
  125. DrawableDocument& doc = getDocument();
  126. DrawableTypeInstance item (doc, state);
  127. OwnedArray <ControlPoint> points;
  128. item.getAllControlPoints (points);
  129. StringArray anchors;
  130. for (int i = 0; i < points.size(); ++i)
  131. {
  132. const RelativePoint p (points.getUnchecked(i)->getPosition());
  133. anchors.addIfNotAlreadyThere (p.x.getAnchorName1());
  134. anchors.addIfNotAlreadyThere (p.x.getAnchorName2());
  135. anchors.addIfNotAlreadyThere (p.y.getAnchorName1());
  136. anchors.addIfNotAlreadyThere (p.y.getAnchorName2());
  137. }
  138. for (int i = 0; i < anchors.size(); ++i)
  139. {
  140. const String anchor (anchors[i]);
  141. if (anchor.isNotEmpty() && ! anchor.startsWith ("parent."))
  142. {
  143. const ValueTree v (doc.findDrawableState (anchor.upToFirstOccurrenceOf (".", false, false), false));
  144. if (v.isValid())
  145. deps.add (v);
  146. }
  147. }
  148. }
  149. const Rectangle<float> getObjectPositionFloat (const ValueTree& state)
  150. {
  151. if (drawable != 0)
  152. {
  153. Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (state).getID());
  154. if (d != 0)
  155. return d->getBounds();
  156. }
  157. return Rectangle<float>();
  158. }
  159. void setObjectPositionFloat (const ValueTree& state, const Rectangle<float>& newPos)
  160. {
  161. if (drawable != 0)
  162. {
  163. Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (state).getID());
  164. if (d != 0)
  165. {
  166. d->refreshFromValueTree (state, &getDocument());
  167. DrawableTypeInstance di (getDocument(), state);
  168. di.setBounds (d, newPos);
  169. }
  170. }
  171. }
  172. const Rectangle<int> getObjectPosition (const ValueTree& state)
  173. {
  174. return getObjectPositionFloat (state).getSmallestIntegerContainer();
  175. }
  176. void transformObject (ValueTree& state, const AffineTransform& transform)
  177. {
  178. if (drawable != 0)
  179. {
  180. Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (state).getID());
  181. if (d != 0)
  182. {
  183. d->refreshFromValueTree (state, &getDocument());
  184. DrawableTypeInstance di (getDocument(), state);
  185. di.applyTransform (d, transform);
  186. }
  187. }
  188. }
  189. RelativeRectangle getObjectCoords (const ValueTree& state)
  190. {
  191. return RelativeRectangle();
  192. }
  193. //==============================================================================
  194. class ControlPointComponent : public OverlayItemComponent
  195. {
  196. public:
  197. ControlPointComponent (DrawableEditorCanvas* canvas, const ValueTree& drawableState_, int controlPointNum_)
  198. : OverlayItemComponent (canvas), drawableState (drawableState_),
  199. controlPointNum (controlPointNum_), isDragging (false), mouseDownResult (false), selected (false),
  200. sizeNormal (7), sizeOver (11)
  201. {
  202. setRepaintsOnMouseActivity (true);
  203. }
  204. ~ControlPointComponent()
  205. {
  206. }
  207. void paint (Graphics& g)
  208. {
  209. Rectangle<int> r (getLocalBounds());
  210. if (! isMouseOverOrDragging())
  211. r = r.reduced ((sizeOver - sizeNormal) / 2, (sizeOver - sizeNormal) / 2);
  212. g.setColour (Colour (selected ? 0xaaaaaaaa : 0xaa333333));
  213. g.drawRect (r);
  214. g.setColour (Colour (selected ? 0xaa000000 : 0x99ffffff));
  215. g.fillRect (r.reduced (1, 1));
  216. }
  217. bool hitTest (int x, int y)
  218. {
  219. if (isMouseOverOrDragging())
  220. return true;
  221. return getLocalBounds().reduced ((sizeOver - sizeNormal) / 2, (sizeOver - sizeNormal) / 2).contains (x, y);
  222. }
  223. void mouseDown (const MouseEvent& e)
  224. {
  225. isDragging = false;
  226. if (e.mods.isPopupMenu())
  227. {
  228. canvas->showPopupMenu (true);
  229. }
  230. else
  231. {
  232. mouseDownResult = canvas->getSelection().addToSelectionOnMouseDown (selectionId, e.mods);
  233. }
  234. }
  235. void mouseDrag (const MouseEvent& e)
  236. {
  237. if (! (isDragging || e.mouseWasClicked() || e.mods.isPopupMenu()))
  238. {
  239. canvas->getSelection().addToSelectionOnMouseUp (selectionId, e.mods, true, mouseDownResult);
  240. isDragging = true;
  241. canvas->beginDrag (e.withNewPosition (e.getMouseDownPosition()).getEventRelativeTo (getParentComponent()),
  242. ResizableBorderComponent::Zone (ResizableBorderComponent::Zone::centre), false, Point<float>());
  243. }
  244. if (isDragging)
  245. {
  246. canvas->continueDrag (e.getEventRelativeTo (getParentComponent()));
  247. autoScrollForMouseEvent (e);
  248. }
  249. }
  250. void mouseUp (const MouseEvent& e)
  251. {
  252. if (! e.mods.isPopupMenu())
  253. {
  254. if (isDragging)
  255. canvas->endDrag (e.getEventRelativeTo (getParentComponent()));
  256. else
  257. canvas->getSelection().addToSelectionOnMouseUp (selectionId, e.mods, false, mouseDownResult);
  258. }
  259. }
  260. void mouseDoubleClick (const MouseEvent& e)
  261. {
  262. }
  263. class LineComponent : public OverlayItemComponent
  264. {
  265. public:
  266. LineComponent (EditorCanvasBase* canvas)
  267. : OverlayItemComponent (canvas)
  268. {}
  269. ~LineComponent() {}
  270. void setLine (const Line<float>& newLine)
  271. {
  272. if (line != newLine)
  273. {
  274. line = newLine;
  275. setBoundsInTargetSpace (Rectangle<float> (line.getStart(), line.getEnd())
  276. .getSmallestIntegerContainer().expanded (2, 2));
  277. repaint();
  278. }
  279. }
  280. void paint (Graphics& g)
  281. {
  282. g.setColour (Colours::black.withAlpha (0.6f));
  283. g.drawLine (Line<float> (pointToLocalSpace (line.getStart()),
  284. pointToLocalSpace (line.getEnd())), 1.0f);
  285. }
  286. bool hitTest (int, int)
  287. {
  288. return false;
  289. }
  290. private:
  291. Line<float> line;
  292. };
  293. void updatePosition (ControlPoint& point, RelativeCoordinate::NamedCoordinateFinder* nameFinder)
  294. {
  295. selectionId = point.getID();
  296. const Point<float> p (point.getPosition().resolve (nameFinder));
  297. setBoundsInTargetSpace (Rectangle<int> (roundToInt (p.getX()) - sizeOver / 2,
  298. roundToInt (p.getY()) - sizeOver / 2,
  299. sizeOver, sizeOver));
  300. const bool nowSelected = canvas->getSelection().isSelected (selectionId);
  301. if (selected != nowSelected)
  302. {
  303. selected = nowSelected;
  304. repaint();
  305. }
  306. if (point.hasLine())
  307. {
  308. if (line == 0)
  309. {
  310. line = new LineComponent (canvas);
  311. getParentComponent()->addAndMakeVisible (line, 0);
  312. }
  313. line->setLine (Line<float> (p, point.getEndOfLine().resolve (nameFinder)));
  314. }
  315. else
  316. {
  317. line = 0;
  318. }
  319. }
  320. private:
  321. ValueTree drawableState;
  322. int controlPointNum;
  323. bool isDragging, mouseDownResult, selected;
  324. String selectionId;
  325. ScopedPointer <LineComponent> line;
  326. const int sizeNormal, sizeOver;
  327. };
  328. void updateControlPointComponents (Component* parent, OwnedArray<OverlayItemComponent>& comps)
  329. {
  330. if (drawable == 0)
  331. {
  332. comps.clear();
  333. return;
  334. }
  335. DrawableTypeInstance item (getDocument(), controlPointEditingTarget);
  336. OwnedArray <ControlPoint> points;
  337. item.getVisibleControlPoints (points, getSelection());
  338. Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (controlPointEditingTarget).getID());
  339. DrawableComposite* parentDrawable = d->getParent();
  340. comps.removeRange (points.size(), comps.size());
  341. BigInteger requiredIndexes;
  342. requiredIndexes.setRange (0, points.size(), true);
  343. for (int i = 0; i < points.size(); ++i)
  344. {
  345. ControlPointComponent* c = dynamic_cast <ControlPointComponent*> (comps[i]);
  346. if (c == 0)
  347. {
  348. c = new ControlPointComponent (this, controlPointEditingTarget, i);
  349. comps.set (i, c);
  350. parent->addAndMakeVisible (c);
  351. }
  352. c->updatePosition (*points.getUnchecked(i), parentDrawable);
  353. }
  354. }
  355. //==============================================================================
  356. MarkerListBase& getMarkerList (bool isX)
  357. {
  358. return getDocument().getMarkerList (isX);
  359. }
  360. double limitMarkerPosition (double pos)
  361. {
  362. return pos;
  363. }
  364. //==============================================================================
  365. SelectedItems& getSelection()
  366. {
  367. return editor.getSelection();
  368. }
  369. void deselectNonDraggableObjects()
  370. {
  371. }
  372. void findLassoItemsInArea (Array <SelectedItems::ItemType>& itemsFound, const Rectangle<int>& area)
  373. {
  374. const Rectangle<float> floatArea (area.toFloat());
  375. if (drawable != 0)
  376. {
  377. if (isControlPointMode())
  378. {
  379. DrawableTypeInstance item (getDocument(), controlPointEditingTarget);
  380. OwnedArray <ControlPoint> points;
  381. item.getVisibleControlPoints (points, getSelection());
  382. const Rectangle<float> floatArea (area.toFloat());
  383. for (int i = 0; i < points.size(); ++i)
  384. {
  385. const Point<float> p (points.getUnchecked(i)->getPosition().resolve (drawable));
  386. if (floatArea.contains (p))
  387. itemsFound.add (points.getUnchecked(i)->getID());
  388. }
  389. }
  390. else
  391. {
  392. for (int i = drawable->getNumDrawables(); --i >= 0;)
  393. {
  394. Drawable* d = drawable->getDrawable (i);
  395. if (d->getBounds().intersects (floatArea))
  396. itemsFound.add (d->getName());
  397. }
  398. }
  399. }
  400. }
  401. bool isControlPointId (const String& itemId)
  402. {
  403. return itemId.containsChar ('/');
  404. }
  405. //==============================================================================
  406. class ObjectDragOperation : public EditorDragOperation
  407. {
  408. public:
  409. ObjectDragOperation (DrawableEditorCanvas* canvas_, const Point<int>& mousePos,
  410. Component* snapGuideParentComp_, const ResizableBorderComponent::Zone& zone_, bool isRotating)
  411. : EditorDragOperation (canvas_, mousePos, snapGuideParentComp_, zone_, isRotating),
  412. drawableCanvas (canvas_)
  413. {
  414. }
  415. ~ObjectDragOperation() {}
  416. protected:
  417. DrawableDocument& getDocument() throw() { return drawableCanvas->getDocument(); }
  418. void getSnapPointsX (Array<float>& points, bool /*includeCentre*/) { points.add (0.0f); }
  419. void getSnapPointsY (Array<float>& points, bool /*includeCentre*/) { points.add (0.0f); }
  420. UndoManager& getUndoManager() { return *getDocument().getUndoManager(); }
  421. void getObjectDependencies (const ValueTree& state, Array<ValueTree>& deps)
  422. {
  423. drawableCanvas->getObjectPositionDependencies (state, deps);
  424. }
  425. const Rectangle<float> getObjectPosition (const ValueTree& state)
  426. {
  427. return drawableCanvas->getObjectPositionFloat (state);
  428. }
  429. void setObjectPosition (ValueTree& state, const Rectangle<float>& newBounds)
  430. {
  431. drawableCanvas->setObjectPositionFloat (state, newBounds);
  432. }
  433. void transformObject (ValueTree& state, const AffineTransform& transform)
  434. {
  435. drawableCanvas->transformObject (state, transform);
  436. }
  437. float getMarkerPosition (const ValueTree& marker, bool isX)
  438. {
  439. return 0;
  440. }
  441. private:
  442. DrawableEditorCanvas* drawableCanvas;
  443. };
  444. //==============================================================================
  445. class ControlPointDragOperation : public EditorDragOperation
  446. {
  447. public:
  448. ControlPointDragOperation (DrawableEditorCanvas* canvas_,
  449. const DrawableTypeInstance& drawableItem_,
  450. DrawableComposite* drawable_,
  451. const Point<int>& mousePos,
  452. Component* snapGuideParentComp_,
  453. const ResizableBorderComponent::Zone& zone_)
  454. : EditorDragOperation (canvas_, mousePos, snapGuideParentComp_, zone_, false),
  455. drawableCanvas (canvas_), drawableItem (drawableItem_), drawable (drawable_)
  456. {
  457. drawableItem.getVisibleControlPoints (points, canvas_->getSelection());
  458. }
  459. ~ControlPointDragOperation() {}
  460. OwnedArray <ControlPoint> points;
  461. protected:
  462. DrawableDocument& getDocument() throw() { return drawableCanvas->getDocument(); }
  463. void getSnapPointsX (Array<float>& points, bool /*includeCentre*/) { points.add (0.0f); }
  464. void getSnapPointsY (Array<float>& points, bool /*includeCentre*/) { points.add (0.0f); }
  465. UndoManager& getUndoManager() { return *getDocument().getUndoManager(); }
  466. void getObjectDependencies (const ValueTree& state, Array<ValueTree>& deps)
  467. {
  468. drawableCanvas->getObjectPositionDependencies (drawableItem.getState(), deps);
  469. }
  470. const Rectangle<float> getObjectPosition (const ValueTree& state)
  471. {
  472. int index = state [Ids::id_];
  473. ControlPoint* cp = points[index];
  474. if (cp == 0)
  475. return Rectangle<float>();
  476. Point<float> p (cp->getPosition().resolve (drawable));
  477. return Rectangle<float> (p, p);
  478. }
  479. void setObjectPosition (ValueTree& state, const Rectangle<float>& newBounds)
  480. {
  481. int index = state [Ids::id_];
  482. ControlPoint* cp = points[index];
  483. if (cp != 0)
  484. {
  485. RelativePoint p (cp->getPosition());
  486. p.moveToAbsolute (newBounds.getPosition(), drawable);
  487. cp->setPosition (p, getDocument().getUndoManager());
  488. }
  489. }
  490. void transformObject (ValueTree& state, const AffineTransform& transform)
  491. {
  492. }
  493. float getMarkerPosition (const ValueTree& marker, bool isX)
  494. {
  495. return 0;
  496. }
  497. private:
  498. DrawableEditorCanvas* drawableCanvas;
  499. DrawableTypeInstance drawableItem;
  500. DrawableComposite* drawable;
  501. };
  502. //==============================================================================
  503. bool canRotate() const { return true; }
  504. DragOperation* createDragOperation (const Point<int>& mouseDownPos, Component* snapGuideParentComponent,
  505. const ResizableBorderComponent::Zone& zone, bool isRotating)
  506. {
  507. Array<ValueTree> selected, unselected;
  508. EditorDragOperation* drag = 0;
  509. if (isControlPointMode())
  510. {
  511. DrawableTypeInstance item (getDocument(), controlPointEditingTarget);
  512. ControlPointDragOperation* cpd = new ControlPointDragOperation (this, item, drawable, mouseDownPos, snapGuideParentComponent, zone);
  513. drag = cpd;
  514. for (int i = 0; i < cpd->points.size(); ++i)
  515. {
  516. const String pointId (cpd->points.getUnchecked(i)->getID());
  517. ValueTree v (Ids::controlPoint);
  518. v.setProperty (Ids::id_, i, 0);
  519. if (editor.getSelection().isSelected (pointId))
  520. selected.add (v);
  521. else
  522. unselected.add (v);
  523. }
  524. }
  525. else
  526. {
  527. DrawableComposite::ValueTreeWrapper mainGroup (getDocument().getRootDrawableNode());
  528. drag = new ObjectDragOperation (this, mouseDownPos, snapGuideParentComponent, zone, isRotating);
  529. for (int i = mainGroup.getNumDrawables(); --i >= 0;)
  530. {
  531. const ValueTree v (mainGroup.getDrawableState (i));
  532. if (editor.getSelection().isSelected (v[Drawable::ValueTreeWrapperBase::idProperty]))
  533. selected.add (v);
  534. else
  535. unselected.add (v);
  536. }
  537. }
  538. drag->initialise (selected, unselected);
  539. return drag;
  540. }
  541. void timerCallback()
  542. {
  543. stopTimer();
  544. if (! Component::isMouseButtonDownAnywhere())
  545. getUndoManager().beginNewTransaction();
  546. }
  547. //==============================================================================
  548. bool isInterestedInFileDrag (const StringArray& files)
  549. {
  550. for (int i = files.size(); --i >= 0;)
  551. if (File (files[i]).hasFileExtension ("svg;jpg;jpeg;gif;png"))
  552. return true;
  553. return false;
  554. }
  555. void filesDropped (const StringArray& files, int x, int y)
  556. {
  557. for (int i = files.size(); --i >= 0;)
  558. {
  559. const File f (files[i]);
  560. if (f.hasFileExtension ("svg"))
  561. {
  562. ValueTree newItem (getDocument().insertSVG (f, screenSpaceToObjectSpace (Point<int> (x, y).toFloat())));
  563. if (newItem.isValid())
  564. getSelection().selectOnly (Drawable::ValueTreeWrapperBase (newItem).getID());
  565. }
  566. else if (f.hasFileExtension ("jpg;jpeg;gif;png"))
  567. {
  568. }
  569. }
  570. }
  571. //==============================================================================
  572. class DrawableComponent : public Component
  573. {
  574. public:
  575. DrawableComponent (DrawableEditorCanvas* canvas_)
  576. : canvas (canvas_)
  577. {
  578. setOpaque (true);
  579. }
  580. ~DrawableComponent()
  581. {
  582. }
  583. void updateDrawable()
  584. {
  585. repaint();
  586. }
  587. void paint (Graphics& g)
  588. {
  589. canvas->handleUpdateNowIfNeeded();
  590. g.fillAll (Colours::white);
  591. const Point<int> origin (canvas->getOrigin());
  592. g.setOrigin (origin.getX(), origin.getY());
  593. if (origin.getX() > 0)
  594. {
  595. g.setColour (Colour::greyLevel (0.87f));
  596. g.drawVerticalLine (0, -10000.0f, 10000.0f);
  597. }
  598. if (origin.getY() > 0)
  599. {
  600. g.setColour (Colour::greyLevel (0.87f));
  601. g.drawHorizontalLine (0, -10000.0f, 10000.0f);
  602. }
  603. canvas->drawable->draw (g, 1.0f);
  604. }
  605. private:
  606. DrawableEditorCanvas* canvas;
  607. DrawableEditor& getEditor() const { return canvas->getEditor(); }
  608. };
  609. ScopedPointer<DrawableComposite> drawable;
  610. private:
  611. //==============================================================================
  612. DrawableEditor& editor;
  613. };
  614. #endif // __JUCER_DRAWABLEOBJECTCOMPONENT_JUCEHEADER__