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.

228 lines
7.3KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. #include "../../Application/jucer_Headers.h"
  20. #include "jucer_PaintElementGroup.h"
  21. PaintElementGroup::PaintElementGroup (PaintRoutine* pr)
  22. : PaintElement (pr, "Group")
  23. {
  24. }
  25. PaintElementGroup::~PaintElementGroup() {}
  26. void PaintElementGroup::ungroup (const bool undoable)
  27. {
  28. getOwner()->getSelectedElements().deselectAll();
  29. getOwner()->getSelectedPoints().deselectAll();
  30. const int index = getOwner()->indexOfElement (this);
  31. for (int i = 0; i < subElements.size(); ++i)
  32. {
  33. ScopedPointer<XmlElement> xml (subElements.getUnchecked(i)->createXml());
  34. PaintElement* newOne = getOwner()->addElementFromXml (*xml, index, undoable);
  35. getOwner()->getSelectedElements().addToSelection (newOne);
  36. }
  37. getOwner()->removeElement (this, undoable);
  38. }
  39. void PaintElementGroup::groupSelected (PaintRoutine* routine)
  40. {
  41. if (routine->getSelectedElements().getNumSelected() > 1)
  42. {
  43. auto* newGroup = new PaintElementGroup (routine);
  44. int frontIndex = -1;
  45. for (int i = 0; i < routine->getNumElements(); ++i)
  46. {
  47. if (routine->getSelectedElements().isSelected (routine->getElement (i)))
  48. {
  49. ScopedPointer<XmlElement> xml (routine->getElement(i)->createXml());
  50. if (auto* newOne = ObjectTypes::createElementForXml (xml, routine))
  51. newGroup->subElements.add (newOne);
  52. if (i > frontIndex)
  53. frontIndex = i;
  54. }
  55. }
  56. routine->deleteSelected();
  57. auto* g = routine->addNewElement (newGroup, frontIndex, true);
  58. routine->getSelectedElements().selectOnly (g);
  59. }
  60. }
  61. int PaintElementGroup::getNumElements() const noexcept { return subElements.size(); }
  62. PaintElement* PaintElementGroup::getElement (const int index) const noexcept { return subElements [index]; }
  63. int PaintElementGroup::indexOfElement (const PaintElement* element) const noexcept { return subElements.indexOf (element); }
  64. bool PaintElementGroup::containsElement (const PaintElement* element) const
  65. {
  66. if (subElements.contains (element))
  67. return true;
  68. for (int i = subElements.size(); --i >= 0;)
  69. if (PaintElementGroup* pg = dynamic_cast<PaintElementGroup*> (subElements.getUnchecked(i)))
  70. if (pg->containsElement (element))
  71. return true;
  72. return false;
  73. }
  74. //==============================================================================
  75. void PaintElementGroup::setInitialBounds (int /*parentWidth*/, int /*parentHeight*/)
  76. {
  77. }
  78. Rectangle<int> PaintElementGroup::getCurrentBounds (const Rectangle<int>& parentArea) const
  79. {
  80. Rectangle<int> r;
  81. if (subElements.size() > 0)
  82. {
  83. r = subElements.getUnchecked(0)->getCurrentBounds (parentArea);
  84. for (int i = 1; i < subElements.size(); ++i)
  85. r = r.getUnion (subElements.getUnchecked(i)->getCurrentBounds (parentArea));
  86. }
  87. return r;
  88. }
  89. void PaintElementGroup::setCurrentBounds (const Rectangle<int>& b, const Rectangle<int>& parentArea, const bool undoable)
  90. {
  91. Rectangle<int> newBounds (b);
  92. newBounds.setSize (jmax (1, newBounds.getWidth()),
  93. jmax (1, newBounds.getHeight()));
  94. const Rectangle<int> current (getCurrentBounds (parentArea));
  95. if (newBounds != current)
  96. {
  97. const int dx = newBounds.getX() - current.getX();
  98. const int dy = newBounds.getY() - current.getY();
  99. const double scaleStartX = current.getX();
  100. const double scaleStartY = current.getY();
  101. const double scaleX = newBounds.getWidth() / (double) current.getWidth();
  102. const double scaleY = newBounds.getHeight() / (double) current.getHeight();
  103. for (int i = 0; i < subElements.size(); ++i)
  104. {
  105. PaintElement* const e = subElements.getUnchecked(i);
  106. Rectangle<int> pos (e->getCurrentBounds (parentArea));
  107. const int newX = roundToInt ((pos.getX() - scaleStartX) * scaleX + scaleStartX + dx);
  108. const int newY = roundToInt ((pos.getY() - scaleStartY) * scaleY + scaleStartY + dy);
  109. pos.setBounds (newX, newY,
  110. roundToInt ((pos.getRight() - scaleStartX) * scaleX + scaleStartX + dx) - newX,
  111. roundToInt ((pos.getBottom() - scaleStartY) * scaleY + scaleStartY + dy) - newY);
  112. e->setCurrentBounds (pos, parentArea, undoable);
  113. }
  114. }
  115. }
  116. //==============================================================================
  117. void PaintElementGroup::draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
  118. {
  119. for (int i = 0; i < subElements.size(); ++i)
  120. subElements.getUnchecked(i)->draw (g, layout, parentArea);
  121. }
  122. void PaintElementGroup::getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected)
  123. {
  124. if (! multipleSelected)
  125. props.add (new UngroupProperty (this));
  126. }
  127. void PaintElementGroup::fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
  128. {
  129. for (int i = 0; i < subElements.size(); ++i)
  130. subElements.getUnchecked(i)->fillInGeneratedCode (code, paintMethodCode);
  131. }
  132. const char* PaintElementGroup::getTagName() noexcept { return "GROUP"; }
  133. XmlElement* PaintElementGroup::createXml() const
  134. {
  135. XmlElement* e = new XmlElement (getTagName());
  136. for (int i = 0; i < subElements.size(); ++i)
  137. {
  138. XmlElement* const sub = subElements.getUnchecked(i)->createXml();
  139. e->addChildElement (sub);
  140. }
  141. return e;
  142. }
  143. bool PaintElementGroup::loadFromXml (const XmlElement& xml)
  144. {
  145. if (xml.hasTagName (getTagName()))
  146. {
  147. forEachXmlChildElement (xml, e)
  148. if (PaintElement* const pe = ObjectTypes::createElementForXml (e, owner))
  149. subElements.add (pe);
  150. return true;
  151. }
  152. jassertfalse;
  153. return false;
  154. }
  155. void PaintElementGroup::applyCustomPaintSnippets (StringArray& snippets)
  156. {
  157. for (auto* e : subElements)
  158. e->applyCustomPaintSnippets (snippets);
  159. }
  160. PaintElementGroup::UngroupProperty::UngroupProperty (PaintElementGroup* const e)
  161. : ButtonPropertyComponent ("ungroup", false),
  162. element (e)
  163. {
  164. }
  165. void PaintElementGroup::UngroupProperty::buttonClicked()
  166. {
  167. element->ungroup (true);
  168. }
  169. String PaintElementGroup::UngroupProperty::getButtonText() const
  170. {
  171. return "Ungroup";
  172. }