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.

254 lines
8.1KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #ifndef __JUCER_PAINTELEMENTROUNDEDRECTANGLE_JUCEHEADER__
  19. #define __JUCER_PAINTELEMENTROUNDEDRECTANGLE_JUCEHEADER__
  20. #include "jucer_ColouredElement.h"
  21. #include "../jucer_UtilityFunctions.h"
  22. //==============================================================================
  23. class PaintElementRoundedRectangle : public ColouredElement
  24. {
  25. public:
  26. PaintElementRoundedRectangle (PaintRoutine* owner)
  27. : ColouredElement (owner, "Rounded Rectangle", true, false)
  28. {
  29. cornerSize = 10.0;
  30. }
  31. void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
  32. {
  33. double x, y, w, h;
  34. position.getRectangleDouble (x, y, w, h, parentArea, layout);
  35. fillType.setFillType (g, getDocument(), parentArea);
  36. g.fillRoundedRectangle ((float) x, (float) y, (float) w, (float) h, (float) cornerSize);
  37. if (isStrokePresent)
  38. {
  39. strokeType.fill.setFillType (g, getDocument(), parentArea);
  40. g.drawRoundedRectangle ((float) x, (float) y, (float) w, (float) h, (float) cornerSize,
  41. getStrokeType().stroke.getStrokeThickness());
  42. }
  43. }
  44. void getEditableProperties (Array <PropertyComponent*>& properties)
  45. {
  46. properties.add (new CornerSizeProperty (this));
  47. ColouredElement::getEditableProperties (properties);
  48. properties.add (new ShapeToPathProperty (this));
  49. }
  50. //==============================================================================
  51. class SetCornerSizeAction : public PaintElementUndoableAction <PaintElementRoundedRectangle>
  52. {
  53. public:
  54. SetCornerSizeAction (PaintElementRoundedRectangle* const element, const double newSize_)
  55. : PaintElementUndoableAction <PaintElementRoundedRectangle> (element),
  56. newSize (newSize_)
  57. {
  58. oldSize = element->getCornerSize();
  59. }
  60. bool perform()
  61. {
  62. showCorrectTab();
  63. getElement()->setCornerSize (newSize, false);
  64. return true;
  65. }
  66. bool undo()
  67. {
  68. showCorrectTab();
  69. getElement()->setCornerSize (oldSize, false);
  70. return true;
  71. }
  72. private:
  73. double newSize, oldSize;
  74. };
  75. void setCornerSize (const double newSize, const bool undoable)
  76. {
  77. if (newSize != cornerSize)
  78. {
  79. if (undoable)
  80. {
  81. perform (new SetCornerSizeAction (this, newSize),
  82. "Change rounded rectangle corner size");
  83. }
  84. else
  85. {
  86. cornerSize = newSize;
  87. changed();
  88. }
  89. }
  90. }
  91. double getCornerSize() const noexcept { return cornerSize; }
  92. //==============================================================================
  93. void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
  94. {
  95. if (! fillType.isInvisible())
  96. {
  97. String x, y, w, h, s;
  98. positionToCode (position, code.document->getComponentLayout(), x, y, w, h);
  99. fillType.fillInGeneratedCode (code, paintMethodCode);
  100. s << "g.fillRoundedRectangle ("
  101. << castToFloat (x) << ", "
  102. << castToFloat (y) << ", "
  103. << castToFloat (w) << ", "
  104. << castToFloat (h) << ", "
  105. << CodeHelpers::floatLiteral (cornerSize, 3) << ");\n\n";
  106. paintMethodCode += s;
  107. }
  108. if (isStrokePresent && ! strokeType.isInvisible())
  109. {
  110. String x, y, w, h, s;
  111. positionToCode (position, code.document->getComponentLayout(), x, y, w, h);
  112. strokeType.fill.fillInGeneratedCode (code, paintMethodCode);
  113. s << "g.drawRoundedRectangle ("
  114. << castToFloat (x) << ", "
  115. << castToFloat (y) << ", "
  116. << castToFloat (w) << ", "
  117. << castToFloat (h) << ", "
  118. << CodeHelpers::floatLiteral (cornerSize, 3) << ", "
  119. << CodeHelpers::floatLiteral (strokeType.stroke.getStrokeThickness(), 3) << ");\n\n";
  120. paintMethodCode += s;
  121. }
  122. }
  123. static const char* getTagName() noexcept { return "ROUNDRECT"; }
  124. XmlElement* createXml() const
  125. {
  126. XmlElement* const e = new XmlElement (getTagName());
  127. position.applyToXml (*e);
  128. e->setAttribute ("cornerSize", cornerSize);
  129. addColourAttributes (e);
  130. return e;
  131. }
  132. bool loadFromXml (const XmlElement& xml)
  133. {
  134. if (xml.hasTagName (getTagName()))
  135. {
  136. position.restoreFromXml (xml, position);
  137. cornerSize = xml.getDoubleAttribute ("cornerSize", 10.0);
  138. loadColourAttributes (xml);
  139. return true;
  140. }
  141. jassertfalse;
  142. return false;
  143. }
  144. void convertToPath()
  145. {
  146. double x, y, w, h;
  147. getCurrentAbsoluteBoundsDouble (x, y, w, h);
  148. Path path;
  149. path.addRoundedRectangle ((float) x, (float) y, (float) w, (float) h, (float) cornerSize);
  150. convertToNewPathElement (path);
  151. }
  152. private:
  153. double cornerSize;
  154. //==============================================================================
  155. class CornerSizeProperty : public SliderPropertyComponent,
  156. public ChangeListener
  157. {
  158. public:
  159. CornerSizeProperty (PaintElementRoundedRectangle* const owner_)
  160. : SliderPropertyComponent ("corner size", 1.0, 200.0, 0.5, 0.4),
  161. owner (owner_)
  162. {
  163. owner->getDocument()->addChangeListener (this);
  164. }
  165. ~CornerSizeProperty()
  166. {
  167. owner->getDocument()->removeChangeListener (this);
  168. }
  169. void setValue (double newValue)
  170. {
  171. owner->getDocument()->getUndoManager().undoCurrentTransactionOnly();
  172. owner->setCornerSize (newValue, true);
  173. }
  174. double getValue() const { return owner->getCornerSize(); }
  175. void changeListenerCallback (ChangeBroadcaster*) { refresh(); }
  176. private:
  177. PaintElementRoundedRectangle* const owner;
  178. };
  179. //==============================================================================
  180. class ShapeToPathProperty : public ButtonPropertyComponent
  181. {
  182. public:
  183. ShapeToPathProperty (PaintElementRoundedRectangle* const e)
  184. : ButtonPropertyComponent ("path", false),
  185. element (e)
  186. {
  187. }
  188. void buttonClicked()
  189. {
  190. element->convertToPath();
  191. }
  192. String getButtonText() const
  193. {
  194. return "convert to a path";
  195. }
  196. private:
  197. PaintElementRoundedRectangle* const element;
  198. };
  199. };
  200. #endif // __JUCER_PAINTELEMENTROUNDEDRECTANGLE_JUCEHEADER__