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.

447 lines
14KB

  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 Timer
  25. {
  26. public:
  27. DrawableEditorCanvas (DrawableEditor& editor_)
  28. : editor (editor_)
  29. {
  30. initialise();
  31. getDocument().getRoot().addListener (this);
  32. }
  33. ~DrawableEditorCanvas()
  34. {
  35. getDocument().getRoot().removeListener (this);
  36. shutdown();
  37. }
  38. Component* createComponentHolder()
  39. {
  40. return new DrawableComponent (this);
  41. }
  42. void documentChanged()
  43. {
  44. DrawableDocument& doc = getDocument();
  45. if (drawable == 0)
  46. {
  47. Drawable* newDrawable = Drawable::createFromValueTree (doc.getRootDrawableNode().getState(), &doc);
  48. drawable = dynamic_cast <DrawableComposite*> (newDrawable);
  49. jassert (drawable != 0);
  50. getComponentHolder()->repaint();
  51. }
  52. else
  53. {
  54. const Rectangle<float> damage (drawable->refreshFromValueTree (doc.getRootDrawableNode().getState(), &doc));
  55. getComponentHolder()->repaint (damage.getSmallestIntegerContainer());
  56. }
  57. startTimer (500);
  58. }
  59. const Rectangle<int> getCanvasBounds()
  60. {
  61. return drawable->getBounds().getSmallestIntegerContainer();
  62. }
  63. void setCanvasBounds (const Rectangle<int>& newBounds) {}
  64. bool canResizeCanvas() const { return false; }
  65. MarkerListBase& getMarkerList (bool isX)
  66. {
  67. return getDocument().getMarkerList (isX);
  68. }
  69. double limitMarkerPosition (double pos)
  70. {
  71. return pos;
  72. }
  73. const SelectedItems::ItemType findObjectIdAt (const Point<int>& position)
  74. {
  75. if (drawable != 0)
  76. {
  77. for (int i = drawable->getNumDrawables(); --i >= 0;)
  78. {
  79. Drawable* d = drawable->getDrawable (i);
  80. if (d->hitTest ((float) position.getX(), (float) position.getY()))
  81. return d->getName();
  82. }
  83. }
  84. return String::empty;
  85. }
  86. void showPopupMenu (bool isClickOnSelectedObject)
  87. {
  88. PopupMenu m;
  89. if (isClickOnSelectedObject)
  90. {
  91. m.addCommandItem (commandManager, CommandIDs::toFront);
  92. m.addCommandItem (commandManager, CommandIDs::toBack);
  93. m.addSeparator();
  94. m.addCommandItem (commandManager, StandardApplicationCommandIDs::del);
  95. const int r = m.show();
  96. (void) r;
  97. }
  98. else
  99. {
  100. getDocument().addNewItemMenuItems (m);
  101. const int r = m.show();
  102. getDocument().performNewItemMenuItem (r);
  103. }
  104. }
  105. void objectDoubleClicked (const MouseEvent& e, const ValueTree& state)
  106. {
  107. }
  108. bool hasSizeGuides() const { return false; }
  109. const ValueTree getObjectState (const String& objectId)
  110. {
  111. return getDocument().findDrawableState (objectId, false);
  112. }
  113. void getObjectPositionDependencies (const ValueTree& state, Array<ValueTree>& deps)
  114. {
  115. DrawableDocument& doc = getDocument();
  116. DrawableTypeInstance item (doc, state);
  117. Array <RelativePoint> points;
  118. item.getAllControlPoints (points);
  119. StringArray anchors;
  120. for (int i = 0; i < points.size(); ++i)
  121. {
  122. anchors.addIfNotAlreadyThere (points.getReference(i).x.getAnchorName1());
  123. anchors.addIfNotAlreadyThere (points.getReference(i).x.getAnchorName2());
  124. anchors.addIfNotAlreadyThere (points.getReference(i).y.getAnchorName1());
  125. anchors.addIfNotAlreadyThere (points.getReference(i).y.getAnchorName2());
  126. }
  127. for (int i = 0; i < anchors.size(); ++i)
  128. {
  129. const String anchor (anchors[i]);
  130. if (anchor.isNotEmpty() && ! anchor.startsWith ("parent."))
  131. {
  132. const ValueTree v (doc.findDrawableState (anchor.upToFirstOccurrenceOf (".", false, false), false));
  133. if (v.isValid())
  134. deps.add (v);
  135. }
  136. }
  137. }
  138. const Rectangle<float> getObjectPositionFloat (const ValueTree& state)
  139. {
  140. if (drawable != 0)
  141. {
  142. Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (state).getID());
  143. if (d != 0)
  144. return d->getBounds();
  145. }
  146. return Rectangle<float>();
  147. }
  148. void setObjectPositionFloat (const ValueTree& state, const Rectangle<float>& newPos)
  149. {
  150. if (drawable != 0)
  151. {
  152. Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (state).getID());
  153. if (d != 0)
  154. {
  155. d->refreshFromValueTree (state, &getDocument());
  156. DrawableTypeInstance di (getDocument(), state);
  157. di.setBounds (d, newPos);
  158. }
  159. }
  160. }
  161. const Rectangle<int> getObjectPosition (const ValueTree& state)
  162. {
  163. return getObjectPositionFloat (state).getSmallestIntegerContainer();
  164. }
  165. RelativeRectangle getObjectCoords (const ValueTree& state)
  166. {
  167. return RelativeRectangle();
  168. }
  169. class ControlPointComponent : public OverlayItemComponent
  170. {
  171. public:
  172. ControlPointComponent (DrawableEditorCanvas* canvas)
  173. : OverlayItemComponent (canvas)
  174. {
  175. }
  176. ~ControlPointComponent()
  177. {
  178. }
  179. void paint (Graphics& g)
  180. {
  181. g.fillAll (Colours::pink);
  182. }
  183. void mouseDown (const MouseEvent& e)
  184. {
  185. }
  186. void mouseDrag (const MouseEvent& e)
  187. {
  188. }
  189. void mouseUp (const MouseEvent& e)
  190. {
  191. }
  192. void updatePosition (const RelativePoint& point, RelativeCoordinate::NamedCoordinateFinder* nameFinder)
  193. {
  194. const Point<float> p (point.resolve (nameFinder));
  195. setBoundsInTargetSpace (Rectangle<int> (roundToInt (p.getX()) - 2, roundToInt (p.getY()) - 2, 5, 5));
  196. }
  197. };
  198. void updateExtraComponentsForObject (const ValueTree& state, Component* parent, OwnedArray<OverlayItemComponent>& comps)
  199. {
  200. if (drawable == 0)
  201. {
  202. comps.clear();
  203. return;
  204. }
  205. DrawableTypeInstance item (getDocument(), state);
  206. Array<RelativePoint> points;
  207. item.getAllControlPoints (points);
  208. Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (state).getID());
  209. DrawableComposite* parentDrawable = d->getParent();
  210. comps.removeRange (points.size(), comps.size());
  211. BigInteger requiredIndexes;
  212. requiredIndexes.setRange (0, points.size(), true);
  213. for (int i = 0; i < points.size(); ++i)
  214. {
  215. ControlPointComponent* c = dynamic_cast <ControlPointComponent*> (comps[i]);
  216. if (c == 0)
  217. {
  218. c = new ControlPointComponent (this);
  219. comps.set (i, c);
  220. parent->addAndMakeVisible (c);
  221. }
  222. c->updatePosition (points.getReference(i), parentDrawable);
  223. }
  224. }
  225. SelectedItems& getSelection()
  226. {
  227. return editor.getSelection();
  228. }
  229. void deselectNonDraggableObjects()
  230. {
  231. }
  232. void findLassoItemsInArea (Array <SelectedItems::ItemType>& itemsFound, const Rectangle<int>& area)
  233. {
  234. const Rectangle<float> floatArea (area.toFloat());
  235. if (drawable != 0)
  236. {
  237. for (int i = drawable->getNumDrawables(); --i >= 0;)
  238. {
  239. Drawable* d = drawable->getDrawable (i);
  240. if (d->getBounds().intersects (floatArea))
  241. itemsFound.add (d->getName());
  242. }
  243. }
  244. }
  245. //==============================================================================
  246. class DragOperation : public EditorDragOperation
  247. {
  248. public:
  249. DragOperation (DrawableEditorCanvas* canvas_,
  250. const MouseEvent& e, const Point<int>& mousePos,
  251. Component* snapGuideParentComp_,
  252. const ResizableBorderComponent::Zone& zone_)
  253. : EditorDragOperation (canvas_, e, mousePos, snapGuideParentComp_, zone_)
  254. {
  255. }
  256. ~DragOperation()
  257. {
  258. getUndoManager().beginNewTransaction();
  259. }
  260. protected:
  261. DrawableDocument& getDocument() throw() { return static_cast <DrawableEditorCanvas*> (canvas)->getDocument(); }
  262. void getSnapPointsX (Array<float>& points, bool /*includeCentre*/) { points.add (0.0f); }
  263. void getSnapPointsY (Array<float>& points, bool /*includeCentre*/) { points.add (0.0f); }
  264. UndoManager& getUndoManager() { return *getDocument().getUndoManager(); }
  265. void getObjectDependencies (const ValueTree& state, Array<ValueTree>& deps)
  266. {
  267. static_cast <DrawableEditorCanvas*> (canvas)->getObjectPositionDependencies (state, deps);
  268. }
  269. const Rectangle<float> getObjectPosition (const ValueTree& state)
  270. {
  271. return static_cast <DrawableEditorCanvas*> (canvas)->getObjectPositionFloat (state);
  272. }
  273. void setObjectPosition (ValueTree& state, const Rectangle<float>& newBounds)
  274. {
  275. static_cast <DrawableEditorCanvas*> (canvas)->setObjectPositionFloat (state, newBounds);
  276. }
  277. float getMarkerPosition (const ValueTree& marker, bool isX)
  278. {
  279. return 0;
  280. }
  281. };
  282. DragOperation* createDragOperation (const MouseEvent& e, Component* snapGuideParentComponent,
  283. const ResizableBorderComponent::Zone& zone)
  284. {
  285. DragOperation* d = new DragOperation (this, e, e.getPosition() - origin, snapGuideParentComponent, zone);
  286. Array<ValueTree> selected, unselected;
  287. DrawableComposite::ValueTreeWrapper mainGroup (getDocument().getRootDrawableNode());
  288. for (int i = mainGroup.getNumDrawables(); --i >= 0;)
  289. {
  290. const ValueTree v (mainGroup.getDrawableState (i));
  291. if (editor.getSelection().isSelected (v[Drawable::ValueTreeWrapperBase::idProperty]))
  292. selected.add (v);
  293. else
  294. unselected.add (v);
  295. }
  296. d->initialise (selected, unselected);
  297. return d;
  298. }
  299. UndoManager& getUndoManager()
  300. {
  301. return *getDocument().getUndoManager();
  302. }
  303. DrawableEditor& getEditor() throw() { return editor; }
  304. DrawableDocument& getDocument() throw() { return editor.getDocument(); }
  305. void timerCallback()
  306. {
  307. stopTimer();
  308. if (! Component::isMouseButtonDownAnywhere())
  309. getUndoManager().beginNewTransaction();
  310. }
  311. //==============================================================================
  312. class DrawableComponent : public Component
  313. {
  314. public:
  315. DrawableComponent (DrawableEditorCanvas* canvas_)
  316. : canvas (canvas_)
  317. {
  318. setOpaque (true);
  319. }
  320. ~DrawableComponent()
  321. {
  322. }
  323. void updateDrawable()
  324. {
  325. repaint();
  326. }
  327. void paint (Graphics& g)
  328. {
  329. canvas->handleUpdateNowIfNeeded();
  330. g.fillAll (Colours::white);
  331. const Point<int> origin (canvas->getOrigin());
  332. g.setOrigin (origin.getX(), origin.getY());
  333. if (origin.getX() > 0)
  334. {
  335. g.setColour (Colour::greyLevel (0.87f));
  336. g.drawVerticalLine (0, -10000.0f, 10000.0f);
  337. }
  338. if (origin.getY() > 0)
  339. {
  340. g.setColour (Colour::greyLevel (0.87f));
  341. g.drawHorizontalLine (0, -10000.0f, 10000.0f);
  342. }
  343. canvas->drawable->draw (g, 1.0f);
  344. }
  345. private:
  346. DrawableEditorCanvas* canvas;
  347. DrawableEditor& getEditor() const { return canvas->getEditor(); }
  348. };
  349. ScopedPointer<DrawableComposite> drawable;
  350. private:
  351. //==============================================================================
  352. DrawableEditor& editor;
  353. };
  354. #endif // __JUCER_DRAWABLEOBJECTCOMPONENT_JUCEHEADER__