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.

227 lines
7.3KB

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