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.

420 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. #include "jucer_DrawableDocument.h"
  19. //==============================================================================
  20. namespace Tags
  21. {
  22. const Identifier drawableTag ("DRAWABLE");
  23. const Identifier markersGroupXTag ("MARKERS_X");
  24. const Identifier markersGroupYTag ("MARKERS_Y");
  25. }
  26. //==============================================================================
  27. DrawableDocument::DrawableDocument (Project* project_)
  28. : project (project_),
  29. root (Tags::drawableTag),
  30. saveAsXml (true),
  31. needsSaving (false)
  32. {
  33. DrawableComposite dc;
  34. root.addChild (dc.createValueTree(), -1, 0);
  35. setName ("Drawable");
  36. checkRootObject();
  37. root.addListener (this);
  38. }
  39. DrawableDocument::~DrawableDocument()
  40. {
  41. root.removeListener (this);
  42. }
  43. ValueTree DrawableDocument::getRootDrawableNode() const
  44. {
  45. return root.getChild (0);
  46. }
  47. void DrawableDocument::checkRootObject()
  48. {
  49. if (markersX == 0)
  50. markersX = new MarkerList (*this, true);
  51. if (markersY == 0)
  52. markersY = new MarkerList (*this, false);
  53. if ((int) getCanvasWidth().getValue() <= 0)
  54. getCanvasWidth() = 500;
  55. if ((int) getCanvasHeight().getValue() <= 0)
  56. getCanvasHeight() = 500;
  57. }
  58. const String DrawableDocument::getIdFor (const ValueTree& object)
  59. {
  60. return object [Ids::id_];
  61. }
  62. //==============================================================================
  63. void DrawableDocument::setName (const String& name)
  64. {
  65. root.setProperty (Ids::name, name, getUndoManager());
  66. }
  67. const String DrawableDocument::getName() const
  68. {
  69. return root [Ids::name];
  70. }
  71. void DrawableDocument::addMissingIds (ValueTree tree) const
  72. {
  73. if (! tree.hasProperty (Ids::id_))
  74. tree.setProperty (Ids::id_, createAlphaNumericUID(), 0);
  75. for (int i = tree.getNumChildren(); --i >= 0;)
  76. addMissingIds (tree.getChild(i));
  77. }
  78. bool DrawableDocument::hasChangedSinceLastSave() const
  79. {
  80. return needsSaving;
  81. }
  82. bool DrawableDocument::reload (const File& drawableFile)
  83. {
  84. ScopedPointer <InputStream> stream (drawableFile.createInputStream());
  85. if (stream != 0 && load (*stream))
  86. {
  87. checkRootObject();
  88. undoManager.clearUndoHistory();
  89. needsSaving = false;
  90. return true;
  91. }
  92. return false;
  93. }
  94. bool DrawableDocument::save (const File& drawableFile)
  95. {
  96. TemporaryFile tempFile (drawableFile);
  97. ScopedPointer <OutputStream> out (tempFile.getFile().createOutputStream());
  98. if (out == 0)
  99. return false;
  100. save (*out);
  101. needsSaving = ! tempFile.overwriteTargetFileWithTemporary();
  102. return ! needsSaving;
  103. }
  104. void DrawableDocument::save (OutputStream& output)
  105. {
  106. if (saveAsXml)
  107. {
  108. ScopedPointer <XmlElement> xml (root.createXml());
  109. jassert (xml != 0);
  110. if (xml != 0)
  111. xml->writeToStream (output, String::empty, false, false);
  112. }
  113. else
  114. {
  115. root.writeToStream (output);
  116. }
  117. }
  118. bool DrawableDocument::load (InputStream& input)
  119. {
  120. int64 originalPos = input.getPosition();
  121. ValueTree loadedTree ("dummy");
  122. XmlDocument xmlDoc (input.readEntireStreamAsString());
  123. ScopedPointer <XmlElement> xml (xmlDoc.getDocumentElement());
  124. if (xml != 0)
  125. {
  126. loadedTree = ValueTree::fromXml (*xml);
  127. }
  128. else
  129. {
  130. input.setPosition (originalPos);
  131. loadedTree = ValueTree::readFromStream (input);
  132. }
  133. if (loadedTree.hasType (Tags::drawableTag))
  134. {
  135. addMissingIds (loadedTree);
  136. root.removeListener (this);
  137. root = loadedTree;
  138. root.addListener (this);
  139. valueTreeParentChanged (loadedTree);
  140. needsSaving = false;
  141. undoManager.clearUndoHistory();
  142. return true;
  143. }
  144. return false;
  145. }
  146. void DrawableDocument::changed()
  147. {
  148. needsSaving = true;
  149. sendChangeMessage (this);
  150. }
  151. //==============================================================================
  152. static const Colour getRandomColour()
  153. {
  154. return Colours::red.withHue (Random::getSystemRandom().nextFloat());
  155. }
  156. void DrawableDocument::addDrawable (Drawable& d)
  157. {
  158. DrawableComposite dc;
  159. dc.insertDrawable (d.createCopy());
  160. ValueTree dcNode (dc.createValueTree());
  161. ValueTree subNode (dcNode.getChild(0));
  162. dcNode.removeChild (subNode, 0);
  163. addMissingIds (subNode);
  164. getRootDrawableNode().addChild (subNode, -1, getUndoManager());
  165. }
  166. void DrawableDocument::addRectangle()
  167. {
  168. Path p;
  169. p.addRectangle ((float) Random::getSystemRandom().nextInt (500),
  170. (float) Random::getSystemRandom().nextInt (500),
  171. 100.0f, 100.0f);
  172. DrawablePath d;
  173. d.setPath (p);
  174. d.setFill (FillType (getRandomColour()));
  175. addDrawable (d);
  176. }
  177. void DrawableDocument::addCircle()
  178. {
  179. Path p;
  180. p.addEllipse ((float) Random::getSystemRandom().nextInt (500),
  181. (float) Random::getSystemRandom().nextInt (500),
  182. 100.0f, 100.0f);
  183. DrawablePath d;
  184. d.setPath (p);
  185. d.setFill (FillType (getRandomColour()));
  186. addDrawable (d);
  187. }
  188. void DrawableDocument::addImage (const File& imageFile)
  189. {
  190. jassertfalse
  191. DrawableImage d;
  192. addDrawable (d);
  193. }
  194. //==============================================================================
  195. void DrawableDocument::valueTreePropertyChanged (ValueTree& tree, const Identifier& name)
  196. {
  197. changed();
  198. }
  199. void DrawableDocument::valueTreeChildrenChanged (ValueTree& tree)
  200. {
  201. changed();
  202. }
  203. void DrawableDocument::valueTreeParentChanged (ValueTree& tree)
  204. {
  205. changed();
  206. }
  207. //==============================================================================
  208. const Coordinate DrawableDocument::findNamedCoordinate (const String& objectName, const String& edge) const
  209. {
  210. if (objectName == "parent")
  211. {
  212. if (edge == "right") return Coordinate ((double) getCanvasWidth().getValue(), true);
  213. if (edge == "bottom") return Coordinate ((double) getCanvasHeight().getValue(), false);
  214. }
  215. if (objectName.isNotEmpty() && edge.isNotEmpty())
  216. {
  217. /* const ValueTree comp (getComponentWithMemberName (compName));
  218. if (comp.isValid())
  219. {
  220. const RectangleCoordinates coords (getCoordsFor (comp));
  221. if (edge == Coordinate::leftName) return coords.left;
  222. if (edge == "right") return coords.right;
  223. if (edge == "top") return coords.top;
  224. if (edge == "bottom") return coords.bottom;
  225. }*/
  226. }
  227. {
  228. const ValueTree marker (getMarkerListX().getMarkerNamed (objectName));
  229. if (marker.isValid())
  230. return getMarkerListX().getCoordinate (marker);
  231. }
  232. {
  233. const ValueTree marker (getMarkerListY().getMarkerNamed (objectName));
  234. if (marker.isValid())
  235. return getMarkerListY().getCoordinate (marker);
  236. }
  237. return Coordinate();
  238. }
  239. DrawableDocument::MarkerList::MarkerList (DrawableDocument& document_, bool isX_)
  240. : MarkerListBase (document_.getRoot().getChildWithName (isX_ ? Tags::markersGroupXTag : Tags::markersGroupYTag), isX_),
  241. document (document_)
  242. {
  243. }
  244. const Coordinate DrawableDocument::MarkerList::findNamedCoordinate (const String& objectName, const String& edge) const
  245. {
  246. if (objectName == "parent")
  247. {
  248. if (edge == "right") return Coordinate ((double) document.getCanvasWidth().getValue(), true);
  249. if (edge == "bottom") return Coordinate ((double) document.getCanvasHeight().getValue(), false);
  250. }
  251. const ValueTree marker (getMarkerNamed (objectName));
  252. if (marker.isValid())
  253. return getCoordinate (marker);
  254. return Coordinate();
  255. }
  256. bool DrawableDocument::MarkerList::createProperties (Array <PropertyComponent*>& props, const String& itemId)
  257. {
  258. ValueTree marker (group.getChildWithProperty (getIdProperty(), itemId));
  259. if (marker.isValid())
  260. {
  261. props.add (new TextPropertyComponent (getNameAsValue (marker), "Marker Name", 256, false));
  262. // props.add (new MarkerPositionComponent (document, "Position", marker,
  263. // marker.getPropertyAsValue (markerPosProperty, document.getUndoManager()),
  264. // contains (marker)));
  265. return true;
  266. }
  267. return false;
  268. }
  269. void DrawableDocument::addMarkerMenuItem (int i, const Coordinate& coord, const String& objectName, const String& edge, PopupMenu& menu,
  270. bool isAnchor1, const String& fullCoordName)
  271. {
  272. // Coordinate requestedCoord (findNamedCoordinate (objectName, edge, coord.isHorizontal()));
  273. // menu.addItem (i, name,
  274. // ! (name == fullCoordName || requestedCoord.referencesIndirectly (fullCoordName, *this)),
  275. // name == (isAnchor1 ? coord.getAnchor1() : coord.getAnchor2()));
  276. }
  277. void DrawableDocument::MarkerList::addMarkerMenuItems (const ValueTree& markerState, const Coordinate& coord, PopupMenu& menu, bool isAnchor1)
  278. {
  279. /* const String fullCoordName (getName (markerState));
  280. if (coord.isHorizontal())
  281. {
  282. document.addMarkerMenuItem (1, coord, "parent", "left", menu, isAnchor1, fullCoordName);
  283. document.addMarkerMenuItem (2, coord, "parent", "right", menu, isAnchor1, fullCoordName);
  284. }
  285. else
  286. {
  287. document.addMarkerMenuItem (1, coord, "parent", "top", menu, isAnchor1, fullCoordName);
  288. document.addMarkerMenuItem (2, coord, "parent", "bottom", menu, isAnchor1, fullCoordName);
  289. }
  290. menu.addSeparator();
  291. const MarkerList& markerList = document.getMarkerList (coord.isHorizontal());
  292. for (int i = 0; i < markerList.size(); ++i)
  293. document.addMarkerMenuItem (100 + i, coord, markerList.getName (markerList.getMarker (i)),
  294. String::empty, menu, isAnchor1, fullCoordName);*/
  295. }
  296. const String DrawableDocument::MarkerList::getChosenMarkerMenuItem (const Coordinate& coord, int i) const
  297. {
  298. /* if (i == 1) return coord.isHorizontal() ? "parent.left" : "parent.top";
  299. if (i == 2) return coord.isHorizontal() ? "parent.right" : "parent.bottom";
  300. const MarkerList& markerList = document.getMarkerList (coord.isHorizontal());
  301. if (i >= 100 && i < 10000)
  302. return markerList.getName (markerList.getMarker (i - 100));
  303. jassertfalse;*/
  304. return String::empty;
  305. }
  306. UndoManager* DrawableDocument::MarkerList::getUndoManager() const
  307. {
  308. return document.getUndoManager();
  309. }
  310. const String DrawableDocument::MarkerList::getNonexistentMarkerName (const String& name)
  311. {
  312. return document.getNonexistentMarkerName (name);
  313. }
  314. const String DrawableDocument::getNonexistentMarkerName (const String& name)
  315. {
  316. String n (CodeHelpers::makeValidIdentifier (name, false, true, false));
  317. int suffix = 2;
  318. while (markersX->getMarkerNamed (n).isValid() || markersY->getMarkerNamed (n).isValid())
  319. n = n.trimCharactersAtEnd ("0123456789") + String (suffix++);
  320. return n;
  321. }
  322. void DrawableDocument::MarkerList::renameAnchor (const String& oldName, const String& newName)
  323. {
  324. document.renameAnchor (oldName, newName);
  325. }
  326. void DrawableDocument::renameAnchor (const String& oldName, const String& newName)
  327. {
  328. }