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.

236 lines
7.7KB

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