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.

241 lines
8.1KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 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_PAINTELEMENTGROUP_JUCEHEADER__
  19. #define __JUCER_PAINTELEMENTGROUP_JUCEHEADER__
  20. #include "jucer_PaintElement.h"
  21. #include "../jucer_ObjectTypes.h"
  22. //==============================================================================
  23. class PaintElementGroup : public PaintElement
  24. {
  25. public:
  26. PaintElementGroup (PaintRoutine* owner)
  27. : PaintElement (owner, "Group")
  28. {
  29. }
  30. void ungroup (const bool undoable)
  31. {
  32. getOwner()->getSelectedElements().deselectAll();
  33. getOwner()->getSelectedPoints().deselectAll();
  34. const int index = getOwner()->indexOfElement (this);
  35. for (int i = 0; i < subElements.size(); ++i)
  36. {
  37. ScopedPointer<XmlElement> xml (subElements.getUnchecked(i)->createXml());
  38. PaintElement* newOne = getOwner()->addElementFromXml (*xml, index, undoable);
  39. getOwner()->getSelectedElements().addToSelection (newOne);
  40. }
  41. getOwner()->removeElement (this, undoable);
  42. }
  43. static void groupSelected (PaintRoutine* const routine)
  44. {
  45. if (routine->getSelectedElements().getNumSelected() > 1)
  46. {
  47. PaintElementGroup* newGroup = new PaintElementGroup (routine);
  48. int frontIndex = -1;
  49. for (int i = 0; i < routine->getNumElements(); ++i)
  50. {
  51. if (routine->getSelectedElements().isSelected (routine->getElement (i)))
  52. {
  53. ScopedPointer<XmlElement> xml (routine->getElement(i)->createXml());
  54. if (PaintElement* newOne = ObjectTypes::createElementForXml (xml, routine))
  55. newGroup->subElements.add (newOne);
  56. if (i > frontIndex)
  57. frontIndex = i;
  58. }
  59. }
  60. routine->deleteSelected();
  61. PaintElement* const g = routine->addNewElement (newGroup, frontIndex, true);
  62. routine->getSelectedElements().selectOnly (g);
  63. }
  64. }
  65. int getNumElements() const noexcept { return subElements.size(); }
  66. PaintElement* getElement (const int index) const noexcept { return subElements [index]; }
  67. int indexOfElement (const PaintElement* element) const noexcept { return subElements.indexOf (element); }
  68. bool containsElement (const PaintElement* element) const
  69. {
  70. if (subElements.contains (element))
  71. return true;
  72. for (int i = subElements.size(); --i >= 0;)
  73. if (PaintElementGroup* pg = dynamic_cast <PaintElementGroup*> (subElements.getUnchecked(i)))
  74. if (pg->containsElement (element))
  75. return true;
  76. return false;
  77. }
  78. //==============================================================================
  79. void setInitialBounds (int /*parentWidth*/, int /*parentHeight*/)
  80. {
  81. }
  82. Rectangle<int> getCurrentBounds (const Rectangle<int>& parentArea) const
  83. {
  84. Rectangle<int> r;
  85. if (subElements.size() > 0)
  86. {
  87. r = subElements.getUnchecked(0)->getCurrentBounds (parentArea);
  88. for (int i = 1; i < subElements.size(); ++i)
  89. r = r.getUnion (subElements.getUnchecked(i)->getCurrentBounds (parentArea));
  90. }
  91. return r;
  92. }
  93. void setCurrentBounds (const Rectangle<int>& b, const Rectangle<int>& parentArea, const bool undoable)
  94. {
  95. Rectangle<int> newBounds (b);
  96. newBounds.setSize (jmax (1, newBounds.getWidth()),
  97. jmax (1, newBounds.getHeight()));
  98. const Rectangle<int> current (getCurrentBounds (parentArea));
  99. if (newBounds != current)
  100. {
  101. const int dx = newBounds.getX() - current.getX();
  102. const int dy = newBounds.getY() - current.getY();
  103. const double scaleStartX = current.getX();
  104. const double scaleStartY = current.getY();
  105. const double scaleX = newBounds.getWidth() / (double) current.getWidth();
  106. const double scaleY = newBounds.getHeight() / (double) current.getHeight();
  107. for (int i = 0; i < subElements.size(); ++i)
  108. {
  109. PaintElement* const e = subElements.getUnchecked(i);
  110. Rectangle<int> pos (e->getCurrentBounds (parentArea));
  111. const int newX = roundToInt ((pos.getX() - scaleStartX) * scaleX + scaleStartX + dx);
  112. const int newY = roundToInt ((pos.getY() - scaleStartY) * scaleY + scaleStartY + dy);
  113. pos.setBounds (newX, newY,
  114. roundToInt ((pos.getRight() - scaleStartX) * scaleX + scaleStartX + dx) - newX,
  115. roundToInt ((pos.getBottom() - scaleStartY) * scaleY + scaleStartY + dy) - newY);
  116. e->setCurrentBounds (pos, parentArea, undoable);
  117. }
  118. }
  119. }
  120. //==============================================================================
  121. void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
  122. {
  123. for (int i = 0; i < subElements.size(); ++i)
  124. subElements.getUnchecked(i)->draw (g, layout, parentArea);
  125. }
  126. void getEditableProperties (Array <PropertyComponent*>& properties)
  127. {
  128. properties.add (new UngroupProperty (this));
  129. }
  130. void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
  131. {
  132. for (int i = 0; i < subElements.size(); ++i)
  133. subElements.getUnchecked(i)->fillInGeneratedCode (code, paintMethodCode);
  134. }
  135. static const char* getTagName() noexcept { return "GROUP"; }
  136. XmlElement* createXml() const
  137. {
  138. XmlElement* e = new XmlElement (getTagName());
  139. for (int i = 0; i < subElements.size(); ++i)
  140. {
  141. XmlElement* const sub = subElements.getUnchecked(i)->createXml();
  142. e->addChildElement (sub);
  143. }
  144. return e;
  145. }
  146. bool loadFromXml (const XmlElement& xml)
  147. {
  148. if (xml.hasTagName (getTagName()))
  149. {
  150. forEachXmlChildElement (xml, e)
  151. if (PaintElement* const pe = ObjectTypes::createElementForXml (e, owner))
  152. subElements.add (pe);
  153. return true;
  154. }
  155. jassertfalse;
  156. return false;
  157. }
  158. private:
  159. OwnedArray <PaintElement> subElements;
  160. class UngroupProperty : public ButtonPropertyComponent
  161. {
  162. public:
  163. UngroupProperty (PaintElementGroup* const e)
  164. : ButtonPropertyComponent ("ungroup", false),
  165. element (e)
  166. {
  167. }
  168. void buttonClicked()
  169. {
  170. element->ungroup (true);
  171. }
  172. String getButtonText() const
  173. {
  174. return "Ungroup";
  175. }
  176. private:
  177. PaintElementGroup* const element;
  178. };
  179. };
  180. #endif // __JUCER_PAINTELEMENTGROUP_JUCEHEADER__