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.

220 lines
7.1KB

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