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.

240 lines
7.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #ifndef __JUCER_PAINTELEMENTGROUP_JUCEHEADER__
  18. #define __JUCER_PAINTELEMENTGROUP_JUCEHEADER__
  19. #include "jucer_PaintElement.h"
  20. #include "../jucer_ObjectTypes.h"
  21. //==============================================================================
  22. class PaintElementGroup : public PaintElement
  23. {
  24. public:
  25. PaintElementGroup (PaintRoutine* pr)
  26. : PaintElement (pr, "Group")
  27. {
  28. }
  29. void ungroup (const bool undoable)
  30. {
  31. getOwner()->getSelectedElements().deselectAll();
  32. getOwner()->getSelectedPoints().deselectAll();
  33. const int index = getOwner()->indexOfElement (this);
  34. for (int i = 0; i < subElements.size(); ++i)
  35. {
  36. ScopedPointer<XmlElement> xml (subElements.getUnchecked(i)->createXml());
  37. PaintElement* newOne = getOwner()->addElementFromXml (*xml, index, undoable);
  38. getOwner()->getSelectedElements().addToSelection (newOne);
  39. }
  40. getOwner()->removeElement (this, undoable);
  41. }
  42. static void groupSelected (PaintRoutine* const routine)
  43. {
  44. if (routine->getSelectedElements().getNumSelected() > 1)
  45. {
  46. PaintElementGroup* newGroup = new PaintElementGroup (routine);
  47. int frontIndex = -1;
  48. for (int i = 0; i < routine->getNumElements(); ++i)
  49. {
  50. if (routine->getSelectedElements().isSelected (routine->getElement (i)))
  51. {
  52. ScopedPointer<XmlElement> xml (routine->getElement(i)->createXml());
  53. if (PaintElement* newOne = ObjectTypes::createElementForXml (xml, routine))
  54. newGroup->subElements.add (newOne);
  55. if (i > frontIndex)
  56. frontIndex = i;
  57. }
  58. }
  59. routine->deleteSelected();
  60. PaintElement* const g = routine->addNewElement (newGroup, frontIndex, true);
  61. routine->getSelectedElements().selectOnly (g);
  62. }
  63. }
  64. int getNumElements() const noexcept { return subElements.size(); }
  65. PaintElement* getElement (const int index) const noexcept { return subElements [index]; }
  66. int indexOfElement (const PaintElement* element) const noexcept { return subElements.indexOf (element); }
  67. bool containsElement (const PaintElement* element) const
  68. {
  69. if (subElements.contains (element))
  70. return true;
  71. for (int i = subElements.size(); --i >= 0;)
  72. if (PaintElementGroup* pg = dynamic_cast <PaintElementGroup*> (subElements.getUnchecked(i)))
  73. if (pg->containsElement (element))
  74. return true;
  75. return false;
  76. }
  77. //==============================================================================
  78. void setInitialBounds (int /*parentWidth*/, int /*parentHeight*/)
  79. {
  80. }
  81. Rectangle<int> getCurrentBounds (const Rectangle<int>& parentArea) const
  82. {
  83. Rectangle<int> r;
  84. if (subElements.size() > 0)
  85. {
  86. r = subElements.getUnchecked(0)->getCurrentBounds (parentArea);
  87. for (int i = 1; i < subElements.size(); ++i)
  88. r = r.getUnion (subElements.getUnchecked(i)->getCurrentBounds (parentArea));
  89. }
  90. return r;
  91. }
  92. void setCurrentBounds (const Rectangle<int>& b, const Rectangle<int>& parentArea, const bool undoable)
  93. {
  94. Rectangle<int> newBounds (b);
  95. newBounds.setSize (jmax (1, newBounds.getWidth()),
  96. jmax (1, newBounds.getHeight()));
  97. const Rectangle<int> current (getCurrentBounds (parentArea));
  98. if (newBounds != current)
  99. {
  100. const int dx = newBounds.getX() - current.getX();
  101. const int dy = newBounds.getY() - current.getY();
  102. const double scaleStartX = current.getX();
  103. const double scaleStartY = current.getY();
  104. const double scaleX = newBounds.getWidth() / (double) current.getWidth();
  105. const double scaleY = newBounds.getHeight() / (double) current.getHeight();
  106. for (int i = 0; i < subElements.size(); ++i)
  107. {
  108. PaintElement* const e = subElements.getUnchecked(i);
  109. Rectangle<int> pos (e->getCurrentBounds (parentArea));
  110. const int newX = roundToInt ((pos.getX() - scaleStartX) * scaleX + scaleStartX + dx);
  111. const int newY = roundToInt ((pos.getY() - scaleStartY) * scaleY + scaleStartY + dy);
  112. pos.setBounds (newX, newY,
  113. roundToInt ((pos.getRight() - scaleStartX) * scaleX + scaleStartX + dx) - newX,
  114. roundToInt ((pos.getBottom() - scaleStartY) * scaleY + scaleStartY + dy) - newY);
  115. e->setCurrentBounds (pos, parentArea, undoable);
  116. }
  117. }
  118. }
  119. //==============================================================================
  120. void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
  121. {
  122. for (int i = 0; i < subElements.size(); ++i)
  123. subElements.getUnchecked(i)->draw (g, layout, parentArea);
  124. }
  125. void getEditableProperties (Array<PropertyComponent*>& props)
  126. {
  127. props.add (new UngroupProperty (this));
  128. }
  129. void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
  130. {
  131. for (int i = 0; i < subElements.size(); ++i)
  132. subElements.getUnchecked(i)->fillInGeneratedCode (code, paintMethodCode);
  133. }
  134. static const char* getTagName() noexcept { return "GROUP"; }
  135. XmlElement* createXml() const
  136. {
  137. XmlElement* e = new XmlElement (getTagName());
  138. for (int i = 0; i < subElements.size(); ++i)
  139. {
  140. XmlElement* const sub = subElements.getUnchecked(i)->createXml();
  141. e->addChildElement (sub);
  142. }
  143. return e;
  144. }
  145. bool loadFromXml (const XmlElement& xml)
  146. {
  147. if (xml.hasTagName (getTagName()))
  148. {
  149. forEachXmlChildElement (xml, e)
  150. if (PaintElement* const pe = ObjectTypes::createElementForXml (e, owner))
  151. subElements.add (pe);
  152. return true;
  153. }
  154. jassertfalse;
  155. return false;
  156. }
  157. private:
  158. OwnedArray <PaintElement> subElements;
  159. class UngroupProperty : public ButtonPropertyComponent
  160. {
  161. public:
  162. UngroupProperty (PaintElementGroup* const e)
  163. : ButtonPropertyComponent ("ungroup", false),
  164. element (e)
  165. {
  166. }
  167. void buttonClicked()
  168. {
  169. element->ungroup (true);
  170. }
  171. String getButtonText() const
  172. {
  173. return "Ungroup";
  174. }
  175. private:
  176. PaintElementGroup* const element;
  177. };
  178. };
  179. #endif // __JUCER_PAINTELEMENTGROUP_JUCEHEADER__