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.

365 lines
12KB

  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_COMPONENTEDITORCANVAS_H_37C33B56__
  19. #define __JUCER_COMPONENTEDITORCANVAS_H_37C33B56__
  20. //==============================================================================
  21. class ComponentEditorCanvas : public EditorCanvasBase,
  22. public Timer
  23. {
  24. public:
  25. //==============================================================================
  26. ComponentEditorCanvas (ComponentEditor& editor_)
  27. : editor (editor_)
  28. {
  29. background = ImageCache::getFromMemory (BinaryData::brushed_aluminium_png, BinaryData::brushed_aluminium_pngSize);
  30. initialise();
  31. getDocument().getRoot().addListener (this);
  32. }
  33. ~ComponentEditorCanvas()
  34. {
  35. getDocument().getRoot().removeListener (this);
  36. shutdown();
  37. }
  38. ComponentEditor& getEditor() { return editor; }
  39. ComponentDocument& getDocument() { return editor.getDocument(); }
  40. void timerCallback()
  41. {
  42. stopTimer();
  43. if (! Component::isMouseButtonDownAnywhere())
  44. getDocument().beginNewTransaction();
  45. }
  46. Component* createComponentHolder()
  47. {
  48. return new ComponentHolder (getDocument().getBackgroundColour());
  49. }
  50. void documentChanged()
  51. {
  52. getDocument().updateComponentsIn (getComponentHolder());
  53. startTimer (500);
  54. }
  55. void fillBackground (Graphics& g)
  56. {
  57. g.setTiledImageFill (background, 0, 0, 1.0f);
  58. g.fillAll();
  59. }
  60. const Rectangle<int> getCanvasBounds()
  61. {
  62. return Rectangle<int> (0, 0, getDocument().getCanvasWidth().getValue(),
  63. getDocument().getCanvasHeight().getValue());
  64. }
  65. void setCanvasBounds (const Rectangle<int>& newBounds)
  66. {
  67. jassert (newBounds.getPosition().isOrigin());
  68. getDocument().getCanvasWidth() = newBounds.getWidth();
  69. getDocument().getCanvasHeight() = newBounds.getHeight();
  70. }
  71. bool canResizeCanvas() const { return true; }
  72. ComponentDocument::MarkerList& getMarkerList (bool isX)
  73. {
  74. return getDocument().getMarkerList (isX);
  75. }
  76. double limitMarkerPosition (double pos)
  77. {
  78. return jmax (0.0, pos);
  79. }
  80. const SelectedItems::ItemType findObjectIdAt (const Point<int>& position)
  81. {
  82. for (int i = getComponentHolder()->getNumChildComponents(); --i >= 0;)
  83. {
  84. Component* const c = getComponentHolder()->getChildComponent(i);
  85. if (c->getBounds().contains (position))
  86. return ComponentDocument::getJucerIDFor (c);
  87. }
  88. return String::empty;
  89. }
  90. void showPopupMenu (bool isClickOnSelectedObject)
  91. {
  92. if (isClickOnSelectedObject)
  93. {
  94. PopupMenu m;
  95. m.addCommandItem (commandManager, CommandIDs::toFront);
  96. m.addCommandItem (commandManager, CommandIDs::toBack);
  97. m.addSeparator();
  98. m.addCommandItem (commandManager, StandardApplicationCommandIDs::del);
  99. const int r = m.show();
  100. (void) r;
  101. }
  102. else
  103. {
  104. editor.showNewComponentMenu (0);
  105. }
  106. }
  107. void objectDoubleClicked (const MouseEvent& e, const ValueTree& state)
  108. {
  109. getDocument().componentDoubleClicked (e, state);
  110. }
  111. const ValueTree getObjectState (const String& objectId)
  112. {
  113. return getDocument().getComponentWithID (objectId);
  114. }
  115. const Rectangle<int> getObjectPosition (const ValueTree& state)
  116. {
  117. return getDocument().getCoordsFor (state).resolve (&getDocument()).getSmallestIntegerContainer();
  118. }
  119. bool hasSizeGuides() const { return true; }
  120. RelativeRectangle getObjectCoords (const ValueTree& state)
  121. {
  122. return getDocument().getCoordsFor (state);
  123. }
  124. void updateControlPointComponents (Component* parent, OwnedArray<OverlayItemComponent>& existingComps)
  125. {
  126. }
  127. SelectedItems& getSelection()
  128. {
  129. return editor.getSelection();
  130. }
  131. void deselectNonDraggableObjects()
  132. {
  133. editor.deselectNonComponents();
  134. }
  135. void findLassoItemsInArea (Array <SelectedItems::ItemType>& itemsFound, const Rectangle<int>& area)
  136. {
  137. for (int i = getComponentHolder()->getNumChildComponents(); --i >= 0;)
  138. {
  139. Component* c = getComponentHolder()->getChildComponent(i);
  140. if (c->getBounds().intersects (area))
  141. itemsFound.add (ComponentDocument::getJucerIDFor (c));
  142. }
  143. }
  144. //==============================================================================
  145. class DragOperation : public EditorDragOperation
  146. {
  147. public:
  148. DragOperation (ComponentEditorCanvas* canvas_,
  149. const Point<int>& mousePos,
  150. Component* snapGuideParentComp_,
  151. const ResizableBorderComponent::Zone& zone_)
  152. : EditorDragOperation (canvas_, mousePos, snapGuideParentComp_, zone_, false)
  153. {
  154. }
  155. ~DragOperation()
  156. {
  157. }
  158. protected:
  159. ComponentDocument& getDocument() throw() { return static_cast <ComponentEditorCanvas*> (canvas)->getDocument(); }
  160. void getSnapPointsX (Array<float>& points, bool includeCentre)
  161. {
  162. const float width = getDocument().getCanvasWidth().getValue();
  163. points.add (0.0f);
  164. points.add (width);
  165. if (includeCentre)
  166. points.add (width / 2.0f);
  167. }
  168. void getSnapPointsY (Array<float>& points, bool includeCentre)
  169. {
  170. const float height = getDocument().getCanvasHeight().getValue();
  171. points.add (0.0f);
  172. points.add (height);
  173. if (includeCentre)
  174. points.add (height / 2.0f);
  175. }
  176. int getCanvasWidth() { return getDocument().getCanvasWidth().getValue(); }
  177. int getCanvasHeight() { return getDocument().getCanvasHeight().getValue(); }
  178. UndoManager& getUndoManager() { return *getDocument().getUndoManager(); }
  179. void getObjectDependencies (const ValueTree& state, Array<ValueTree>& deps)
  180. {
  181. ComponentDocument& doc = getDocument();
  182. RelativeRectangle pr (doc.getCoordsFor (state));
  183. StringArray anchors;
  184. anchors.addIfNotAlreadyThere (pr.left.getAnchorName1());
  185. anchors.addIfNotAlreadyThere (pr.left.getAnchorName2());
  186. anchors.addIfNotAlreadyThere (pr.top.getAnchorName1());
  187. anchors.addIfNotAlreadyThere (pr.top.getAnchorName2());
  188. anchors.addIfNotAlreadyThere (pr.right.getAnchorName1());
  189. anchors.addIfNotAlreadyThere (pr.right.getAnchorName2());
  190. anchors.addIfNotAlreadyThere (pr.bottom.getAnchorName1());
  191. anchors.addIfNotAlreadyThere (pr.bottom.getAnchorName2());
  192. for (int i = 0; i < anchors.size(); ++i)
  193. {
  194. const String anchor (anchors[i]);
  195. if (anchor.isNotEmpty() && ! anchor.startsWith ("parent."))
  196. {
  197. const ValueTree v (doc.getComponentWithMemberName (anchor.upToFirstOccurrenceOf (".", false, false)));
  198. if (v.isValid())
  199. deps.add (v);
  200. }
  201. }
  202. }
  203. const Rectangle<float> getObjectPosition (const ValueTree& state)
  204. {
  205. ComponentDocument& doc = getDocument();
  206. return doc.getCoordsFor (state).resolve (&doc);
  207. }
  208. void setObjectPosition (ValueTree& state, const Rectangle<float>& newBounds)
  209. {
  210. ComponentDocument& doc = getDocument();
  211. RelativeRectangle pr (doc.getCoordsFor (state));
  212. pr.moveToAbsolute (newBounds, &doc);
  213. doc.setCoordsFor (state, pr);
  214. }
  215. float getMarkerPosition (const ValueTree& marker, bool isX)
  216. {
  217. ComponentDocument& doc = getDocument();
  218. return (float) doc.getMarkerList (isX).getCoordinate (marker).resolve (&doc);
  219. }
  220. void transformObject (ValueTree& state, const AffineTransform& transform)
  221. {
  222. }
  223. };
  224. bool canRotate() const { return false; }
  225. DragOperation* createDragOperation (const Point<int>& mouseDownPos, Component* snapGuideParentComponent,
  226. const ResizableBorderComponent::Zone& zone, bool isRotating)
  227. {
  228. DragOperation* d = new DragOperation (this, mouseDownPos, snapGuideParentComponent, zone);
  229. Array<ValueTree> selected, unselected;
  230. for (int i = getDocument().getNumComponents(); --i >= 0;)
  231. {
  232. const ValueTree v (getDocument().getComponent (i));
  233. if (editor.getSelection().isSelected (v [ComponentDocument::idProperty]))
  234. selected.add (v);
  235. else
  236. unselected.add (v);
  237. }
  238. d->initialise (selected, unselected);
  239. return d;
  240. }
  241. UndoManager& getUndoManager()
  242. {
  243. return *getDocument().getUndoManager();
  244. }
  245. private:
  246. //==============================================================================
  247. ComponentEditor& editor;
  248. Image background;
  249. class ComponentHolder : public Component,
  250. public Value::Listener
  251. {
  252. public:
  253. ComponentHolder (const Value& backgroundColour_)
  254. : backgroundColour (backgroundColour_)
  255. {
  256. setOpaque (true);
  257. updateColour();
  258. backgroundColour.addListener (this);
  259. }
  260. ~ComponentHolder()
  261. {
  262. deleteAllChildren();
  263. }
  264. void updateColour()
  265. {
  266. Colour newColour (Colours::white);
  267. if (backgroundColour.toString().isNotEmpty())
  268. newColour = Colour::fromString (backgroundColour.toString());
  269. if (newColour != colour)
  270. {
  271. colour = newColour;
  272. repaint();
  273. }
  274. }
  275. void paint (Graphics& g)
  276. {
  277. if (colour.isOpaque())
  278. g.fillAll (colour);
  279. else
  280. g.fillCheckerBoard (0, 0, getWidth(), getHeight(), 24, 24,
  281. Colour (0xffeeeeee).overlaidWith (colour),
  282. Colour (0xffffffff).overlaidWith (colour));
  283. }
  284. void valueChanged (Value&)
  285. {
  286. updateColour();
  287. }
  288. private:
  289. Value backgroundColour;
  290. Colour colour;
  291. };
  292. };
  293. #endif // __JUCER_COMPONENTEDITORCANVAS_H_37C33B56__