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.

642 lines
23KB

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