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.

562 lines
17KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software 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_PAINTELEMENTTEXT_JUCEHEADER__
  18. #define __JUCER_PAINTELEMENTTEXT_JUCEHEADER__
  19. #include "jucer_ColouredElement.h"
  20. #include "../properties/jucer_FontPropertyComponent.h"
  21. #include "../properties/jucer_JustificationProperty.h"
  22. //==============================================================================
  23. class PaintElementText : public ColouredElement
  24. {
  25. public:
  26. PaintElementText (PaintRoutine* pr)
  27. : ColouredElement (pr, "Text", false, false),
  28. text ("Your text goes here"),
  29. font (15.0f),
  30. typefaceName (FontPropertyComponent::getDefaultFont()),
  31. justification (Justification::centred)
  32. {
  33. fillType.colour = Colours::black;
  34. position.rect.setWidth (200);
  35. position.rect.setHeight (30);
  36. }
  37. //==============================================================================
  38. void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
  39. {
  40. fillType.setFillType (g, getDocument(), parentArea);
  41. font = FontPropertyComponent::applyNameToFont (typefaceName, font);
  42. g.setFont (font);
  43. g.drawText (replaceStringTranslations (text, owner->getDocument()),
  44. position.getRectangle (parentArea, layout), justification, true);
  45. }
  46. static String replaceStringTranslations (String s, JucerDocument* document)
  47. {
  48. s = s.replace ("%%getName()%%", document->getComponentName());
  49. s = s.replace ("%%getButtonText()%%", document->getComponentName());
  50. return s;
  51. }
  52. void getEditableProperties (Array<PropertyComponent*>& props)
  53. {
  54. ColouredElement::getEditableProperties (props);
  55. props.add (new TextProperty (this));
  56. props.add (new FontNameProperty (this));
  57. props.add (new FontStyleProperty (this));
  58. props.add (new FontSizeProperty (this));
  59. props.add (new TextJustificationProperty (this));
  60. props.add (new TextToPathProperty (this));
  61. }
  62. void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
  63. {
  64. if (! fillType.isInvisible())
  65. {
  66. String r;
  67. fillType.fillInGeneratedCode (code, paintMethodCode);
  68. String x, y, w, h;
  69. positionToCode (position, code.document->getComponentLayout(), x, y, w, h);
  70. r << "g.setFont ("
  71. << FontPropertyComponent::getCompleteFontCode (font, typefaceName)
  72. << ");\ng.drawText ("
  73. << quotedString (text, code.shouldUseTransMacro())
  74. << ",\n "
  75. << x << ", " << y << ", " << w << ", " << h
  76. << ",\n "
  77. << CodeHelpers::justificationToCode (justification)
  78. << ", true);\n\n";
  79. paintMethodCode += r;
  80. }
  81. }
  82. static const char* getTagName() noexcept { return "TEXT"; }
  83. XmlElement* createXml() const
  84. {
  85. XmlElement* e = new XmlElement (getTagName());
  86. position.applyToXml (*e);
  87. addColourAttributes (e);
  88. e->setAttribute ("text", text);
  89. e->setAttribute ("fontname", typefaceName);
  90. e->setAttribute ("fontsize", roundToInt (font.getHeight() * 100.0) / 100.0);
  91. e->setAttribute ("bold", font.isBold());
  92. e->setAttribute ("italic", font.isItalic());
  93. e->setAttribute ("justification", justification.getFlags());
  94. return e;
  95. }
  96. bool loadFromXml (const XmlElement& xml)
  97. {
  98. if (xml.hasTagName (getTagName()))
  99. {
  100. position.restoreFromXml (xml, position);
  101. loadColourAttributes (xml);
  102. text = xml.getStringAttribute ("text", "Hello World");
  103. typefaceName = xml.getStringAttribute ("fontname", FontPropertyComponent::getDefaultFont());
  104. font.setHeight ((float) xml.getDoubleAttribute ("fontsize", 15.0));
  105. font.setBold (xml.getBoolAttribute ("bold", false));
  106. font.setItalic (xml.getBoolAttribute ("italic", false));
  107. justification = Justification (xml.getIntAttribute ("justification", Justification::centred));
  108. return true;
  109. }
  110. jassertfalse;
  111. return false;
  112. }
  113. //==============================================================================
  114. const String& getText() const noexcept { return text; }
  115. class SetTextAction : public PaintElementUndoableAction <PaintElementText>
  116. {
  117. public:
  118. SetTextAction (PaintElementText* const element, const String& newText_)
  119. : PaintElementUndoableAction <PaintElementText> (element),
  120. newText (newText_),
  121. oldText (element->getText())
  122. {
  123. }
  124. bool perform()
  125. {
  126. showCorrectTab();
  127. getElement()->setText (newText, false);
  128. return true;
  129. }
  130. bool undo()
  131. {
  132. showCorrectTab();
  133. getElement()->setText (oldText, false);
  134. return true;
  135. }
  136. private:
  137. String newText, oldText;
  138. };
  139. void setText (const String& t, const bool undoable)
  140. {
  141. if (t != text)
  142. {
  143. if (undoable)
  144. {
  145. perform (new SetTextAction (this, t),
  146. "Change text element text");
  147. }
  148. else
  149. {
  150. text = t;
  151. changed();
  152. }
  153. }
  154. }
  155. //==============================================================================
  156. const Font& getFont() const { return font; }
  157. class SetFontAction : public PaintElementUndoableAction <PaintElementText>
  158. {
  159. public:
  160. SetFontAction (PaintElementText* const element, const Font& newFont_)
  161. : PaintElementUndoableAction <PaintElementText> (element),
  162. newFont (newFont_),
  163. oldFont (element->getFont())
  164. {
  165. }
  166. bool perform()
  167. {
  168. showCorrectTab();
  169. getElement()->setFont (newFont, false);
  170. return true;
  171. }
  172. bool undo()
  173. {
  174. showCorrectTab();
  175. getElement()->setFont (oldFont, false);
  176. return true;
  177. }
  178. private:
  179. Font newFont, oldFont;
  180. };
  181. void setFont (const Font& newFont, const bool undoable)
  182. {
  183. if (font != newFont)
  184. {
  185. if (undoable)
  186. {
  187. perform (new SetFontAction (this, newFont),
  188. "Change text element font");
  189. }
  190. else
  191. {
  192. font = newFont;
  193. changed();
  194. }
  195. }
  196. }
  197. //==============================================================================
  198. class SetTypefaceAction : public PaintElementUndoableAction <PaintElementText>
  199. {
  200. public:
  201. SetTypefaceAction (PaintElementText* const element, const String& newValue_)
  202. : PaintElementUndoableAction <PaintElementText> (element),
  203. newValue (newValue_),
  204. oldValue (element->getTypefaceName())
  205. {
  206. }
  207. bool perform()
  208. {
  209. showCorrectTab();
  210. getElement()->setTypefaceName (newValue, false);
  211. return true;
  212. }
  213. bool undo()
  214. {
  215. showCorrectTab();
  216. getElement()->setTypefaceName (oldValue, false);
  217. return true;
  218. }
  219. private:
  220. String newValue, oldValue;
  221. };
  222. void setTypefaceName (const String& newFontName, const bool undoable)
  223. {
  224. if (undoable)
  225. {
  226. perform (new SetTypefaceAction (this, newFontName),
  227. "Change text element typeface");
  228. }
  229. else
  230. {
  231. typefaceName = newFontName;
  232. changed();
  233. }
  234. }
  235. String getTypefaceName() const noexcept { return typefaceName; }
  236. //==============================================================================
  237. Justification getJustification() const noexcept { return justification; }
  238. class SetJustifyAction : public PaintElementUndoableAction <PaintElementText>
  239. {
  240. public:
  241. SetJustifyAction (PaintElementText* const element, Justification newValue_)
  242. : PaintElementUndoableAction <PaintElementText> (element),
  243. newValue (newValue_),
  244. oldValue (element->getJustification())
  245. {
  246. }
  247. bool perform()
  248. {
  249. showCorrectTab();
  250. getElement()->setJustification (newValue, false);
  251. return true;
  252. }
  253. bool undo()
  254. {
  255. showCorrectTab();
  256. getElement()->setJustification (oldValue, false);
  257. return true;
  258. }
  259. private:
  260. Justification newValue, oldValue;
  261. };
  262. void setJustification (Justification j, const bool undoable)
  263. {
  264. if (justification.getFlags() != j.getFlags())
  265. {
  266. if (undoable)
  267. {
  268. perform (new SetJustifyAction (this, j),
  269. "Change text element justification");
  270. }
  271. else
  272. {
  273. justification = j;
  274. changed();
  275. }
  276. }
  277. }
  278. void convertToPath()
  279. {
  280. font = FontPropertyComponent::applyNameToFont (typefaceName, font);
  281. const Rectangle<int> r (getCurrentAbsoluteBounds());
  282. GlyphArrangement arr;
  283. arr.addCurtailedLineOfText (font, text,
  284. 0.0f, 0.0f, (float) r.getWidth(),
  285. true);
  286. arr.justifyGlyphs (0, arr.getNumGlyphs(),
  287. (float) r.getX(), (float) r.getY(),
  288. (float) r.getWidth(), (float) r.getHeight(),
  289. justification);
  290. Path path;
  291. arr.createPath (path);
  292. convertToNewPathElement (path);
  293. }
  294. private:
  295. String text;
  296. Font font;
  297. String typefaceName;
  298. Justification justification;
  299. Array <Justification> justificationTypes;
  300. //==============================================================================
  301. class TextProperty : public TextPropertyComponent,
  302. public ChangeListener
  303. {
  304. public:
  305. TextProperty (PaintElementText* const e)
  306. : TextPropertyComponent ("text", 2048, false),
  307. element (e)
  308. {
  309. element->getDocument()->addChangeListener (this);
  310. }
  311. ~TextProperty()
  312. {
  313. element->getDocument()->removeChangeListener (this);
  314. }
  315. void setText (const String& newText) { element->setText (newText, true); }
  316. String getText() const { return element->getText(); }
  317. void changeListenerCallback (ChangeBroadcaster*) { refresh(); }
  318. private:
  319. PaintElementText* const element;
  320. };
  321. //==============================================================================
  322. class FontNameProperty : public FontPropertyComponent,
  323. public ChangeListener
  324. {
  325. public:
  326. FontNameProperty (PaintElementText* const e)
  327. : FontPropertyComponent ("font"),
  328. element (e)
  329. {
  330. element->getDocument()->addChangeListener (this);
  331. }
  332. ~FontNameProperty()
  333. {
  334. element->getDocument()->removeChangeListener (this);
  335. }
  336. void setTypefaceName (const String& newFontName) { element->setTypefaceName (newFontName, true); }
  337. String getTypefaceName() const { return element->getTypefaceName(); }
  338. void changeListenerCallback (ChangeBroadcaster*) { refresh(); }
  339. private:
  340. PaintElementText* const element;
  341. };
  342. //==============================================================================
  343. class FontStyleProperty : public ChoicePropertyComponent,
  344. public ChangeListener
  345. {
  346. public:
  347. FontStyleProperty (PaintElementText* const e)
  348. : ChoicePropertyComponent ("style"),
  349. element (e)
  350. {
  351. element->getDocument()->addChangeListener (this);
  352. choices.add ("normal");
  353. choices.add ("bold");
  354. choices.add ("italic");
  355. choices.add ("bold + italic");
  356. }
  357. ~FontStyleProperty()
  358. {
  359. element->getDocument()->removeChangeListener (this);
  360. }
  361. void setIndex (int newIndex)
  362. {
  363. Font f (element->getFont());
  364. f.setBold (newIndex == 1 || newIndex == 3);
  365. f.setItalic (newIndex == 2 || newIndex == 3);
  366. element->setFont (f, true);
  367. }
  368. int getIndex() const
  369. {
  370. if (element->getFont().isBold() && element->getFont().isItalic())
  371. return 3;
  372. else if (element->getFont().isBold())
  373. return 1;
  374. else if (element->getFont().isItalic())
  375. return 2;
  376. return 0;
  377. }
  378. void changeListenerCallback (ChangeBroadcaster*) { refresh(); }
  379. private:
  380. PaintElementText* const element;
  381. };
  382. //==============================================================================
  383. class FontSizeProperty : public SliderPropertyComponent,
  384. public ChangeListener
  385. {
  386. public:
  387. FontSizeProperty (PaintElementText* const e)
  388. : SliderPropertyComponent ("size", 1.0, 250.0, 0.1, 0.3),
  389. element (e)
  390. {
  391. element->getDocument()->addChangeListener (this);
  392. }
  393. ~FontSizeProperty()
  394. {
  395. element->getDocument()->removeChangeListener (this);
  396. }
  397. void setValue (double newValue)
  398. {
  399. element->getDocument()->getUndoManager().undoCurrentTransactionOnly();
  400. Font f (element->getFont());
  401. f.setHeight ((float) newValue);
  402. element->setFont (f, true);
  403. }
  404. double getValue() const
  405. {
  406. return element->getFont().getHeight();
  407. }
  408. void changeListenerCallback (ChangeBroadcaster*) { refresh(); }
  409. private:
  410. PaintElementText* const element;
  411. };
  412. //==============================================================================
  413. class TextJustificationProperty : public JustificationProperty,
  414. public ChangeListener
  415. {
  416. public:
  417. TextJustificationProperty (PaintElementText* const e)
  418. : JustificationProperty ("layout", false),
  419. element (e)
  420. {
  421. element->getDocument()->addChangeListener (this);
  422. }
  423. ~TextJustificationProperty()
  424. {
  425. element->getDocument()->removeChangeListener (this);
  426. }
  427. void setJustification (Justification newJustification)
  428. {
  429. element->setJustification (newJustification, true);
  430. }
  431. Justification getJustification() const
  432. {
  433. return element->getJustification();
  434. }
  435. void changeListenerCallback (ChangeBroadcaster*) { refresh(); }
  436. private:
  437. PaintElementText* const element;
  438. };
  439. //==============================================================================
  440. class TextToPathProperty : public ButtonPropertyComponent
  441. {
  442. public:
  443. TextToPathProperty (PaintElementText* const e)
  444. : ButtonPropertyComponent ("path", false),
  445. element (e)
  446. {
  447. }
  448. void buttonClicked()
  449. {
  450. element->convertToPath();
  451. }
  452. String getButtonText() const
  453. {
  454. return "convert text to a path";
  455. }
  456. private:
  457. PaintElementText* const element;
  458. };
  459. };
  460. #endif // __JUCER_PAINTELEMENTTEXT_JUCEHEADER__