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.

253 lines
7.8KB

  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. #ifndef JUCER_PAINTELEMENTROUNDEDRECTANGLE_H_INCLUDED
  18. #define JUCER_PAINTELEMENTROUNDEDRECTANGLE_H_INCLUDED
  19. #include "jucer_ColouredElement.h"
  20. #include "../jucer_UtilityFunctions.h"
  21. //==============================================================================
  22. class PaintElementRoundedRectangle : public ColouredElement
  23. {
  24. public:
  25. PaintElementRoundedRectangle (PaintRoutine* pr)
  26. : ColouredElement (pr, "Rounded Rectangle", true, false)
  27. {
  28. cornerSize = 10.0;
  29. }
  30. void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
  31. {
  32. double x, y, w, h;
  33. position.getRectangleDouble (x, y, w, h, parentArea, layout);
  34. fillType.setFillType (g, getDocument(), parentArea);
  35. g.fillRoundedRectangle ((float) x, (float) y, (float) w, (float) h, (float) cornerSize);
  36. if (isStrokePresent)
  37. {
  38. strokeType.fill.setFillType (g, getDocument(), parentArea);
  39. g.drawRoundedRectangle ((float) x, (float) y, (float) w, (float) h, (float) cornerSize,
  40. getStrokeType().stroke.getStrokeThickness());
  41. }
  42. }
  43. void getEditableProperties (Array<PropertyComponent*>& props)
  44. {
  45. props.add (new CornerSizeProperty (this));
  46. ColouredElement::getEditableProperties (props);
  47. props.add (new ShapeToPathProperty (this));
  48. }
  49. //==============================================================================
  50. class SetCornerSizeAction : public PaintElementUndoableAction <PaintElementRoundedRectangle>
  51. {
  52. public:
  53. SetCornerSizeAction (PaintElementRoundedRectangle* const element, const double newSize_)
  54. : PaintElementUndoableAction <PaintElementRoundedRectangle> (element),
  55. newSize (newSize_)
  56. {
  57. oldSize = element->getCornerSize();
  58. }
  59. bool perform()
  60. {
  61. showCorrectTab();
  62. getElement()->setCornerSize (newSize, false);
  63. return true;
  64. }
  65. bool undo()
  66. {
  67. showCorrectTab();
  68. getElement()->setCornerSize (oldSize, false);
  69. return true;
  70. }
  71. private:
  72. double newSize, oldSize;
  73. };
  74. void setCornerSize (const double newSize, const bool undoable)
  75. {
  76. if (newSize != cornerSize)
  77. {
  78. if (undoable)
  79. {
  80. perform (new SetCornerSizeAction (this, newSize),
  81. "Change rounded rectangle corner size");
  82. }
  83. else
  84. {
  85. cornerSize = newSize;
  86. changed();
  87. }
  88. }
  89. }
  90. double getCornerSize() const noexcept { return cornerSize; }
  91. //==============================================================================
  92. void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
  93. {
  94. if (! fillType.isInvisible())
  95. {
  96. String x, y, w, h, s;
  97. positionToCode (position, code.document->getComponentLayout(), x, y, w, h);
  98. fillType.fillInGeneratedCode (code, paintMethodCode);
  99. s << "g.fillRoundedRectangle ("
  100. << castToFloat (x) << ", "
  101. << castToFloat (y) << ", "
  102. << castToFloat (w) << ", "
  103. << castToFloat (h) << ", "
  104. << CodeHelpers::floatLiteral (cornerSize, 3) << ");\n\n";
  105. paintMethodCode += s;
  106. }
  107. if (isStrokePresent && ! strokeType.isInvisible())
  108. {
  109. String x, y, w, h, s;
  110. positionToCode (position, code.document->getComponentLayout(), x, y, w, h);
  111. strokeType.fill.fillInGeneratedCode (code, paintMethodCode);
  112. s << "g.drawRoundedRectangle ("
  113. << castToFloat (x) << ", "
  114. << castToFloat (y) << ", "
  115. << castToFloat (w) << ", "
  116. << castToFloat (h) << ", "
  117. << CodeHelpers::floatLiteral (cornerSize, 3) << ", "
  118. << CodeHelpers::floatLiteral (strokeType.stroke.getStrokeThickness(), 3) << ");\n\n";
  119. paintMethodCode += s;
  120. }
  121. }
  122. static const char* getTagName() noexcept { return "ROUNDRECT"; }
  123. XmlElement* createXml() const
  124. {
  125. XmlElement* const e = new XmlElement (getTagName());
  126. position.applyToXml (*e);
  127. e->setAttribute ("cornerSize", cornerSize);
  128. addColourAttributes (e);
  129. return e;
  130. }
  131. bool loadFromXml (const XmlElement& xml)
  132. {
  133. if (xml.hasTagName (getTagName()))
  134. {
  135. position.restoreFromXml (xml, position);
  136. cornerSize = xml.getDoubleAttribute ("cornerSize", 10.0);
  137. loadColourAttributes (xml);
  138. return true;
  139. }
  140. jassertfalse;
  141. return false;
  142. }
  143. void convertToPath()
  144. {
  145. double x, y, w, h;
  146. getCurrentAbsoluteBoundsDouble (x, y, w, h);
  147. Path path;
  148. path.addRoundedRectangle ((float) x, (float) y, (float) w, (float) h, (float) cornerSize);
  149. convertToNewPathElement (path);
  150. }
  151. private:
  152. double cornerSize;
  153. //==============================================================================
  154. class CornerSizeProperty : public SliderPropertyComponent,
  155. public ChangeListener
  156. {
  157. public:
  158. CornerSizeProperty (PaintElementRoundedRectangle* const owner_)
  159. : SliderPropertyComponent ("corner size", 1.0, 200.0, 0.5, 0.4),
  160. owner (owner_)
  161. {
  162. owner->getDocument()->addChangeListener (this);
  163. }
  164. ~CornerSizeProperty()
  165. {
  166. owner->getDocument()->removeChangeListener (this);
  167. }
  168. void setValue (double newValue)
  169. {
  170. owner->getDocument()->getUndoManager().undoCurrentTransactionOnly();
  171. owner->setCornerSize (newValue, true);
  172. }
  173. double getValue() const { return owner->getCornerSize(); }
  174. void changeListenerCallback (ChangeBroadcaster*) { refresh(); }
  175. private:
  176. PaintElementRoundedRectangle* const owner;
  177. };
  178. //==============================================================================
  179. class ShapeToPathProperty : public ButtonPropertyComponent
  180. {
  181. public:
  182. ShapeToPathProperty (PaintElementRoundedRectangle* const e)
  183. : ButtonPropertyComponent ("path", false),
  184. element (e)
  185. {
  186. }
  187. void buttonClicked()
  188. {
  189. element->convertToPath();
  190. }
  191. String getButtonText() const
  192. {
  193. return "convert to a path";
  194. }
  195. private:
  196. PaintElementRoundedRectangle* const element;
  197. };
  198. };
  199. #endif // JUCER_PAINTELEMENTROUNDEDRECTANGLE_H_INCLUDED