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.

640 lines
22KB

  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. class LabelHandler : public ComponentTypeHandler
  18. {
  19. public:
  20. LabelHandler()
  21. : ComponentTypeHandler ("Label", "Label", typeid (Label), 150, 24)
  22. {
  23. registerColour (Label::backgroundColourId, "background", "bkgCol");
  24. registerColour (Label::textColourId, "text", "textCol");
  25. registerColour (Label::outlineColourId, "outline", "outlineCol");
  26. registerColour (TextEditor::textColourId, "editor text", "edTextCol");
  27. registerColour (TextEditor::backgroundColourId, "editor bkg", "edBkgCol");
  28. registerColour (TextEditor::highlightColourId, "highlight", "hiliteCol");
  29. }
  30. Component* createNewComponent (JucerDocument*)
  31. {
  32. return new Label ("new label", "label text");
  33. }
  34. XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
  35. {
  36. Label* const l = dynamic_cast <Label*> (comp);
  37. XmlElement* e = ComponentTypeHandler::createXmlFor (comp, layout);
  38. e->setAttribute ("labelText", l->getText());
  39. e->setAttribute ("editableSingleClick", l->isEditableOnSingleClick());
  40. e->setAttribute ("editableDoubleClick", l->isEditableOnDoubleClick());
  41. e->setAttribute ("focusDiscardsChanges", l->doesLossOfFocusDiscardChanges());
  42. e->setAttribute ("fontname", l->getProperties().getWithDefault ("typefaceName", FontPropertyComponent::getDefaultFont()).toString());
  43. e->setAttribute ("fontsize", roundToInt (l->getFont().getHeight() * 100.0) / 100.0);
  44. e->setAttribute ("bold", l->getFont().isBold());
  45. e->setAttribute ("italic", l->getFont().isItalic());
  46. e->setAttribute ("justification", l->getJustificationType().getFlags());
  47. return e;
  48. }
  49. bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
  50. {
  51. Label* const l = dynamic_cast <Label*> (comp);
  52. if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
  53. return false;
  54. Label defaultLabel (String::empty, String::empty);
  55. Font font;
  56. font.setHeight ((float) xml.getDoubleAttribute ("fontsize", 15.0));
  57. font.setBold (xml.getBoolAttribute ("bold", false));
  58. font.setItalic (xml.getBoolAttribute ("italic", false));
  59. l->setFont (font);
  60. l->getProperties().set ("typefaceName", xml.getStringAttribute ("fontname", FontPropertyComponent::getDefaultFont()));
  61. updateLabelFont (l);
  62. l->setJustificationType (Justification (xml.getIntAttribute ("justification", Justification::centred)));
  63. l->setText (xml.getStringAttribute ("labelText", "Label Text"), dontSendNotification);
  64. l->setEditable (xml.getBoolAttribute ("editableSingleClick", defaultLabel.isEditableOnSingleClick()),
  65. xml.getBoolAttribute ("editableDoubleClick", defaultLabel.isEditableOnDoubleClick()),
  66. xml.getBoolAttribute ("focusDiscardsChanges", defaultLabel.doesLossOfFocusDiscardChanges()));
  67. return true;
  68. }
  69. static void updateLabelFont (Label* label)
  70. {
  71. Font f (label->getFont());
  72. f = FontPropertyComponent::applyNameToFont (label->getProperties().getWithDefault ("typefaceName", FontPropertyComponent::getDefaultFont()), f);
  73. label->setFont (f);
  74. }
  75. String getCreationParameters (GeneratedCode& code, Component* component)
  76. {
  77. Label* const l = dynamic_cast <Label*> (component);
  78. return quotedString (component->getName(), false)
  79. + ",\n"
  80. + quotedString (l->getText(), code.shouldUseTransMacro());
  81. }
  82. void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
  83. {
  84. ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
  85. Label* const l = dynamic_cast <Label*> (component);
  86. String s;
  87. s << memberVariableName << "->setFont ("
  88. << FontPropertyComponent::getCompleteFontCode (l->getFont(), l->getProperties().getWithDefault ("typefaceName", FontPropertyComponent::getDefaultFont()))
  89. << ");\n"
  90. << memberVariableName << "->setJustificationType ("
  91. << CodeHelpers::justificationToCode (l->getJustificationType())
  92. << ");\n"
  93. << memberVariableName << "->setEditable ("
  94. << CodeHelpers::boolLiteral (l->isEditableOnSingleClick()) << ", "
  95. << CodeHelpers::boolLiteral (l->isEditableOnDoubleClick()) << ", "
  96. << CodeHelpers::boolLiteral (l->doesLossOfFocusDiscardChanges()) << ");\n"
  97. << getColourIntialisationCode (component, memberVariableName);
  98. if (needsCallback (component))
  99. s << memberVariableName << "->addListener (this);\n";
  100. s << '\n';
  101. code.constructorCode += s;
  102. }
  103. void fillInGeneratedCode (Component* component, GeneratedCode& code)
  104. {
  105. ComponentTypeHandler::fillInGeneratedCode (component, code);
  106. if (needsCallback (component))
  107. {
  108. String& callback = code.getCallbackCode ("public LabelListener",
  109. "void",
  110. "labelTextChanged (Label* labelThatHasChanged)",
  111. true);
  112. if (callback.trim().isNotEmpty())
  113. callback << "else ";
  114. const String memberVariableName (code.document->getComponentLayout()->getComponentMemberVariableName (component));
  115. const String userCodeComment ("UserLabelCode_" + memberVariableName);
  116. callback
  117. << "if (labelThatHasChanged == " << memberVariableName
  118. << ")\n{\n //[" << userCodeComment << "] -- add your label text handling code here..\n //[/" << userCodeComment << "]\n}\n";
  119. }
  120. }
  121. void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
  122. {
  123. ComponentTypeHandler::getEditableProperties (component, document, props);
  124. Label* const l = dynamic_cast <Label*> (component);
  125. props.add (new LabelTextProperty (l, document));
  126. props.add (new LabelJustificationProperty (l, document));
  127. props.add (new FontNameProperty (l, document));
  128. props.add (new FontSizeProperty (l, document));
  129. props.add (new FontStyleProperty (l, document));
  130. addColourProperties (component, document, props);
  131. props.add (new LabelEditableProperty (l, document));
  132. if (l->isEditableOnDoubleClick() || l->isEditableOnSingleClick())
  133. props.add (new LabelLossOfFocusProperty (l, document));
  134. }
  135. static bool needsCallback (Component* label)
  136. {
  137. return ((Label*) label)->isEditableOnSingleClick()
  138. || ((Label*) label)->isEditableOnDoubleClick(); // xxx should be configurable
  139. }
  140. private:
  141. //==============================================================================
  142. class LabelTextProperty : public ComponentTextProperty <Label>
  143. {
  144. public:
  145. LabelTextProperty (Label* comp, JucerDocument& doc)
  146. : ComponentTextProperty <Label> ("text", 10000, true, comp, doc)
  147. {}
  148. void setText (const String& newText)
  149. {
  150. document.perform (new LabelTextChangeAction (component, *document.getComponentLayout(), newText),
  151. "Change Label text");
  152. }
  153. String getText() const
  154. {
  155. return component->getText();
  156. }
  157. private:
  158. class LabelTextChangeAction : public ComponentUndoableAction <Label>
  159. {
  160. public:
  161. LabelTextChangeAction (Label* const comp, ComponentLayout& l, const String& newState_)
  162. : ComponentUndoableAction <Label> (comp, l),
  163. newState (newState_)
  164. {
  165. oldState = comp->getText();
  166. }
  167. bool perform()
  168. {
  169. showCorrectTab();
  170. getComponent()->setText (newState, dontSendNotification);
  171. changed();
  172. return true;
  173. }
  174. bool undo()
  175. {
  176. showCorrectTab();
  177. getComponent()->setText (oldState, dontSendNotification);
  178. changed();
  179. return true;
  180. }
  181. String newState, oldState;
  182. };
  183. };
  184. //==============================================================================
  185. class LabelEditableProperty : public ComponentChoiceProperty <Label>
  186. {
  187. public:
  188. LabelEditableProperty (Label* comp, JucerDocument& doc)
  189. : ComponentChoiceProperty <Label> ("editing", comp, doc)
  190. {
  191. choices.add ("read-only");
  192. choices.add ("edit on single-click");
  193. choices.add ("edit on double-click");
  194. }
  195. void setIndex (int newIndex)
  196. {
  197. document.perform (new LabelEditableChangeAction (component, *document.getComponentLayout(), newIndex),
  198. "Change Label editability");
  199. }
  200. int getIndex() const
  201. {
  202. return component->isEditableOnSingleClick()
  203. ? 1
  204. : (component->isEditableOnDoubleClick() ? 2 : 0);
  205. }
  206. private:
  207. class LabelEditableChangeAction : public ComponentUndoableAction <Label>
  208. {
  209. public:
  210. LabelEditableChangeAction (Label* const comp, ComponentLayout& l, const int newState_)
  211. : ComponentUndoableAction <Label> (comp, l),
  212. newState (newState_)
  213. {
  214. oldState = comp->isEditableOnSingleClick()
  215. ? 1
  216. : (comp->isEditableOnDoubleClick() ? 2 : 0);
  217. }
  218. bool perform()
  219. {
  220. showCorrectTab();
  221. getComponent()->setEditable (newState == 1, newState >= 1, getComponent()->doesLossOfFocusDiscardChanges());
  222. changed();
  223. layout.getSelectedSet().changed();
  224. return true;
  225. }
  226. bool undo()
  227. {
  228. showCorrectTab();
  229. getComponent()->setEditable (oldState == 1, oldState >= 1, getComponent()->doesLossOfFocusDiscardChanges());
  230. changed();
  231. layout.getSelectedSet().changed();
  232. return true;
  233. }
  234. int newState, oldState;
  235. };
  236. };
  237. //==============================================================================
  238. class LabelLossOfFocusProperty : public ComponentChoiceProperty <Label>
  239. {
  240. public:
  241. LabelLossOfFocusProperty (Label* comp, JucerDocument& doc)
  242. : ComponentChoiceProperty <Label> ("focus", comp, doc)
  243. {
  244. choices.add ("loss of focus discards changes");
  245. choices.add ("loss of focus commits changes");
  246. }
  247. void setIndex (int newIndex)
  248. {
  249. document.perform (new LabelFocusLossChangeAction (component, *document.getComponentLayout(), newIndex == 0),
  250. "Change Label focus behaviour");
  251. }
  252. int getIndex() const
  253. {
  254. return component->doesLossOfFocusDiscardChanges() ? 0 : 1;
  255. }
  256. private:
  257. class LabelFocusLossChangeAction : public ComponentUndoableAction <Label>
  258. {
  259. public:
  260. LabelFocusLossChangeAction (Label* const comp, ComponentLayout& l, const bool newState_)
  261. : ComponentUndoableAction <Label> (comp, l),
  262. newState (newState_)
  263. {
  264. oldState = comp->doesLossOfFocusDiscardChanges();
  265. }
  266. bool perform()
  267. {
  268. showCorrectTab();
  269. getComponent()->setEditable (getComponent()->isEditableOnSingleClick(),
  270. getComponent()->isEditableOnDoubleClick(),
  271. newState);
  272. changed();
  273. return true;
  274. }
  275. bool undo()
  276. {
  277. showCorrectTab();
  278. getComponent()->setEditable (getComponent()->isEditableOnSingleClick(),
  279. getComponent()->isEditableOnDoubleClick(),
  280. oldState);
  281. changed();
  282. return true;
  283. }
  284. bool newState, oldState;
  285. };
  286. };
  287. //==============================================================================
  288. class LabelJustificationProperty : public JustificationProperty,
  289. public ChangeListener
  290. {
  291. public:
  292. LabelJustificationProperty (Label* const label_, JucerDocument& doc)
  293. : JustificationProperty ("layout", false),
  294. label (label_),
  295. document (doc)
  296. {
  297. document.addChangeListener (this);
  298. }
  299. ~LabelJustificationProperty()
  300. {
  301. document.removeChangeListener (this);
  302. }
  303. void setJustification (Justification newJustification)
  304. {
  305. document.perform (new LabelJustifyChangeAction (label, *document.getComponentLayout(), newJustification),
  306. "Change Label justification");
  307. }
  308. Justification getJustification() const
  309. {
  310. return label->getJustificationType();
  311. }
  312. void changeListenerCallback (ChangeBroadcaster*) { refresh(); }
  313. private:
  314. Label* const label;
  315. JucerDocument& document;
  316. class LabelJustifyChangeAction : public ComponentUndoableAction <Label>
  317. {
  318. public:
  319. LabelJustifyChangeAction (Label* const comp, ComponentLayout& l, Justification newState_)
  320. : ComponentUndoableAction <Label> (comp, l),
  321. newState (newState_),
  322. oldState (comp->getJustificationType())
  323. {
  324. }
  325. bool perform()
  326. {
  327. showCorrectTab();
  328. getComponent()->setJustificationType (newState);
  329. changed();
  330. return true;
  331. }
  332. bool undo()
  333. {
  334. showCorrectTab();
  335. getComponent()->setJustificationType (oldState);
  336. changed();
  337. return true;
  338. }
  339. Justification newState, oldState;
  340. };
  341. };
  342. //==============================================================================
  343. class FontNameProperty : public FontPropertyComponent,
  344. public ChangeListener
  345. {
  346. public:
  347. FontNameProperty (Label* const label_, JucerDocument& doc)
  348. : FontPropertyComponent ("font"),
  349. label (label_),
  350. document (doc)
  351. {
  352. document.addChangeListener (this);
  353. }
  354. ~FontNameProperty()
  355. {
  356. document.removeChangeListener (this);
  357. }
  358. void setTypefaceName (const String& newFontName)
  359. {
  360. document.perform (new FontNameChangeAction (label, *document.getComponentLayout(), newFontName),
  361. "Change Label typeface");
  362. }
  363. String getTypefaceName() const
  364. {
  365. return label->getProperties().getWithDefault ("typefaceName", FontPropertyComponent::getDefaultFont());
  366. }
  367. void changeListenerCallback (ChangeBroadcaster*) { refresh(); }
  368. private:
  369. Label* const label;
  370. JucerDocument& document;
  371. class FontNameChangeAction : public ComponentUndoableAction <Label>
  372. {
  373. public:
  374. FontNameChangeAction (Label* const comp, ComponentLayout& l, const String& newState_)
  375. : ComponentUndoableAction <Label> (comp, l),
  376. newState (newState_)
  377. {
  378. oldState = comp->getProperties().getWithDefault ("typefaceName", FontPropertyComponent::getDefaultFont());
  379. }
  380. bool perform()
  381. {
  382. showCorrectTab();
  383. getComponent()->getProperties().set ("typefaceName", newState);
  384. LabelHandler::updateLabelFont (getComponent());
  385. changed();
  386. return true;
  387. }
  388. bool undo()
  389. {
  390. showCorrectTab();
  391. getComponent()->getProperties().set ("typefaceName", oldState);
  392. LabelHandler::updateLabelFont (getComponent());
  393. changed();
  394. return true;
  395. }
  396. String newState, oldState;
  397. };
  398. };
  399. //==============================================================================
  400. class FontSizeProperty : public SliderPropertyComponent,
  401. public ChangeListener
  402. {
  403. public:
  404. FontSizeProperty (Label* const label_, JucerDocument& doc)
  405. : SliderPropertyComponent ("size", 1.0, 250.0, 0.1, 0.3),
  406. label (label_),
  407. document (doc)
  408. {
  409. document.addChangeListener (this);
  410. }
  411. ~FontSizeProperty()
  412. {
  413. document.removeChangeListener (this);
  414. }
  415. void setValue (double newValue)
  416. {
  417. document.getUndoManager().undoCurrentTransactionOnly();
  418. document.perform (new FontSizeChangeAction (label, *document.getComponentLayout(), (float) newValue),
  419. "Change Label font size");
  420. }
  421. double getValue() const
  422. {
  423. return label->getFont().getHeight();
  424. }
  425. void changeListenerCallback (ChangeBroadcaster*) { refresh(); }
  426. private:
  427. Label* const label;
  428. JucerDocument& document;
  429. class FontSizeChangeAction : public ComponentUndoableAction <Label>
  430. {
  431. public:
  432. FontSizeChangeAction (Label* const comp, ComponentLayout& l, const float newState_)
  433. : ComponentUndoableAction <Label> (comp, l),
  434. newState (newState_)
  435. {
  436. oldState = comp->getFont().getHeight();
  437. }
  438. bool perform()
  439. {
  440. showCorrectTab();
  441. Font f (getComponent()->getFont());
  442. f.setHeight ((float) newState);
  443. getComponent()->setFont (f);
  444. changed();
  445. return true;
  446. }
  447. bool undo()
  448. {
  449. showCorrectTab();
  450. Font f (getComponent()->getFont());
  451. f.setHeight ((float) oldState);
  452. getComponent()->setFont (f);
  453. changed();
  454. return true;
  455. }
  456. float newState, oldState;
  457. };
  458. };
  459. //==============================================================================
  460. class FontStyleProperty : public ChoicePropertyComponent,
  461. public ChangeListener
  462. {
  463. public:
  464. FontStyleProperty (Label* const label_, JucerDocument& doc)
  465. : ChoicePropertyComponent ("style"),
  466. label (label_),
  467. document (doc)
  468. {
  469. document.addChangeListener (this);
  470. choices.add ("normal");
  471. choices.add ("bold");
  472. choices.add ("italic");
  473. choices.add ("bold + italic");
  474. }
  475. ~FontStyleProperty()
  476. {
  477. document.removeChangeListener (this);
  478. }
  479. void setIndex (int newIndex)
  480. {
  481. Font f (label->getFont());
  482. f.setBold (newIndex == 1 || newIndex == 3);
  483. f.setItalic (newIndex == 2 || newIndex == 3);
  484. document.perform (new FontStyleChangeAction (label, *document.getComponentLayout(), f),
  485. "Change Label font style");
  486. }
  487. int getIndex() const
  488. {
  489. if (label->getFont().isBold() && label->getFont().isItalic())
  490. return 3;
  491. else if (label->getFont().isBold())
  492. return 1;
  493. else if (label->getFont().isItalic())
  494. return 2;
  495. return 0;
  496. }
  497. void changeListenerCallback (ChangeBroadcaster*) { refresh(); }
  498. private:
  499. Label* const label;
  500. JucerDocument& document;
  501. class FontStyleChangeAction : public ComponentUndoableAction <Label>
  502. {
  503. public:
  504. FontStyleChangeAction (Label* const comp, ComponentLayout& l, const Font& newState_)
  505. : ComponentUndoableAction <Label> (comp, l),
  506. newState (newState_)
  507. {
  508. oldState = comp->getFont();
  509. }
  510. bool perform()
  511. {
  512. showCorrectTab();
  513. getComponent()->setFont (newState);
  514. changed();
  515. return true;
  516. }
  517. bool undo()
  518. {
  519. showCorrectTab();
  520. getComponent()->setFont (oldState);
  521. changed();
  522. return true;
  523. }
  524. Font newState, oldState;
  525. };
  526. };
  527. };