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.

430 lines
15KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. class ComboBoxHandler : public ComponentTypeHandler
  20. {
  21. public:
  22. ComboBoxHandler()
  23. : ComponentTypeHandler ("Combo Box", "ComboBox", typeid (ComboBox), 150, 24)
  24. {}
  25. Component* createNewComponent (JucerDocument*)
  26. {
  27. return new ComboBox ("new combo box");
  28. }
  29. XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
  30. {
  31. ComboBox* const c = dynamic_cast<ComboBox*> (comp);
  32. jassert (c != nullptr);
  33. XmlElement* e = ComponentTypeHandler::createXmlFor (comp, layout);
  34. e->setAttribute ("editable", c->isTextEditable());
  35. e->setAttribute ("layout", c->getJustificationType().getFlags());
  36. e->setAttribute ("items", c->getProperties() ["items"].toString());
  37. e->setAttribute ("textWhenNonSelected", c->getTextWhenNothingSelected());
  38. e->setAttribute ("textWhenNoItems", c->getTextWhenNoChoicesAvailable());
  39. return e;
  40. }
  41. bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
  42. {
  43. if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
  44. return false;
  45. ComboBox defaultBox;
  46. ComboBox* const c = dynamic_cast<ComboBox*> (comp);
  47. jassert (c != nullptr);
  48. c->setEditableText (xml.getBoolAttribute ("editable", defaultBox.isTextEditable()));
  49. c->setJustificationType (Justification (xml.getIntAttribute ("layout", defaultBox.getJustificationType().getFlags())));
  50. c->getProperties().set ("items", xml.getStringAttribute ("items", String()));
  51. c->setTextWhenNothingSelected (xml.getStringAttribute ("textWhenNonSelected", defaultBox.getTextWhenNothingSelected()));
  52. c->setTextWhenNoChoicesAvailable (xml.getStringAttribute ("textWhenNoItems", defaultBox.getTextWhenNoChoicesAvailable()));
  53. updateItems (c);
  54. return true;
  55. }
  56. void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
  57. {
  58. ComponentTypeHandler::getEditableProperties (component, document, props);
  59. ComboBox* const c = dynamic_cast<ComboBox*> (component);
  60. jassert (c != nullptr);
  61. props.add (new ComboItemsProperty (c, document));
  62. props.add (new ComboEditableProperty (c, document));
  63. props.add (new ComboJustificationProperty (c, document));
  64. props.add (new ComboTextWhenNoneSelectedProperty (c, document));
  65. props.add (new ComboTextWhenNoItemsProperty (c, document));
  66. }
  67. String getCreationParameters (GeneratedCode&, Component* component)
  68. {
  69. return quotedString (component->getName(), false);
  70. }
  71. void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
  72. {
  73. ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
  74. ComboBox* const c = dynamic_cast<ComboBox*> (component);
  75. jassert (c != nullptr);
  76. String s;
  77. s << memberVariableName << "->setEditableText (" << CodeHelpers::boolLiteral (c->isTextEditable()) << ");\n"
  78. << memberVariableName << "->setJustificationType (" << CodeHelpers::justificationToCode (c->getJustificationType()) << ");\n"
  79. << memberVariableName << "->setTextWhenNothingSelected (" << quotedString (c->getTextWhenNothingSelected(), code.shouldUseTransMacro()) << ");\n"
  80. << memberVariableName << "->setTextWhenNoChoicesAvailable (" << quotedString (c->getTextWhenNoChoicesAvailable(), code.shouldUseTransMacro()) << ");\n";
  81. StringArray lines;
  82. lines.addLines (c->getProperties() ["items"].toString());
  83. int itemId = 1;
  84. for (int i = 0; i < lines.size(); ++i)
  85. {
  86. if (lines[i].trim().isEmpty())
  87. s << memberVariableName << "->addSeparator();\n";
  88. else
  89. s << memberVariableName << "->addItem ("
  90. << quotedString (lines[i], code.shouldUseTransMacro()) << ", " << itemId++ << ");\n";
  91. }
  92. if (needsCallback (component))
  93. s << memberVariableName << "->addListener (this);\n";
  94. s << '\n';
  95. code.constructorCode += s;
  96. }
  97. void fillInGeneratedCode (Component* component, GeneratedCode& code)
  98. {
  99. ComponentTypeHandler::fillInGeneratedCode (component, code);
  100. if (needsCallback (component))
  101. {
  102. String& callback = code.getCallbackCode ("public ComboBoxListener",
  103. "void",
  104. "comboBoxChanged (ComboBox* comboBoxThatHasChanged)",
  105. true);
  106. if (callback.trim().isNotEmpty())
  107. callback << "else ";
  108. const String memberVariableName (code.document->getComponentLayout()->getComponentMemberVariableName (component));
  109. const String userCodeComment ("UserComboBoxCode_" + memberVariableName);
  110. callback
  111. << "if (comboBoxThatHasChanged == " << memberVariableName
  112. << ")\n{\n //[" << userCodeComment << "] -- add your combo box handling code here..\n //[/" << userCodeComment << "]\n}\n";
  113. }
  114. }
  115. static void updateItems (ComboBox* c)
  116. {
  117. StringArray lines;
  118. lines.addLines (c->getProperties() ["items"].toString());
  119. c->clear();
  120. int itemId = 1;
  121. for (int i = 0; i < lines.size(); ++i)
  122. {
  123. if (lines[i].trim().isEmpty())
  124. c->addSeparator();
  125. else
  126. c->addItem (lines[i], itemId++);
  127. }
  128. }
  129. static bool needsCallback (Component*)
  130. {
  131. return true; // xxx should be configurable
  132. }
  133. private:
  134. class ComboEditableProperty : public ComponentBooleanProperty <ComboBox>
  135. {
  136. public:
  137. ComboEditableProperty (ComboBox* comp, JucerDocument& doc)
  138. : ComponentBooleanProperty <ComboBox> ("editable", "Text is editable", "Text is editable", comp, doc)
  139. {
  140. }
  141. void setState (bool newState)
  142. {
  143. document.perform (new ComboEditableChangeAction (component, *document.getComponentLayout(), newState),
  144. "Change combo box editability");
  145. }
  146. bool getState() const
  147. {
  148. return component->isTextEditable();
  149. }
  150. private:
  151. class ComboEditableChangeAction : public ComponentUndoableAction <ComboBox>
  152. {
  153. public:
  154. ComboEditableChangeAction (ComboBox* const comp, ComponentLayout& l, const bool newState_)
  155. : ComponentUndoableAction <ComboBox> (comp, l),
  156. newState (newState_)
  157. {
  158. oldState = comp->isTextEditable();
  159. }
  160. bool perform()
  161. {
  162. showCorrectTab();
  163. getComponent()->setEditableText (newState);
  164. changed();
  165. return true;
  166. }
  167. bool undo()
  168. {
  169. showCorrectTab();
  170. getComponent()->setEditableText (oldState);
  171. changed();
  172. return true;
  173. }
  174. bool newState, oldState;
  175. };
  176. };
  177. //==============================================================================
  178. class ComboJustificationProperty : public JustificationProperty
  179. {
  180. public:
  181. ComboJustificationProperty (ComboBox* comp, JucerDocument& doc)
  182. : JustificationProperty ("text layout", false),
  183. component (comp),
  184. document (doc)
  185. {
  186. }
  187. void setJustification (Justification newJustification)
  188. {
  189. document.perform (new ComboJustifyChangeAction (component, *document.getComponentLayout(), newJustification),
  190. "Change combo box justification");
  191. }
  192. Justification getJustification() const { return component->getJustificationType(); }
  193. private:
  194. ComboBox* const component;
  195. JucerDocument& document;
  196. class ComboJustifyChangeAction : public ComponentUndoableAction <ComboBox>
  197. {
  198. public:
  199. ComboJustifyChangeAction (ComboBox* const comp, ComponentLayout& l, Justification newState_)
  200. : ComponentUndoableAction <ComboBox> (comp, l),
  201. newState (newState_),
  202. oldState (comp->getJustificationType())
  203. {
  204. }
  205. bool perform()
  206. {
  207. showCorrectTab();
  208. getComponent()->setJustificationType (newState);
  209. changed();
  210. return true;
  211. }
  212. bool undo()
  213. {
  214. showCorrectTab();
  215. getComponent()->setJustificationType (oldState);
  216. changed();
  217. return true;
  218. }
  219. Justification newState, oldState;
  220. };
  221. };
  222. //==============================================================================
  223. class ComboItemsProperty : public ComponentTextProperty <ComboBox>
  224. {
  225. public:
  226. ComboItemsProperty (ComboBox* comp, JucerDocument& doc)
  227. : ComponentTextProperty <ComboBox> ("items", 10000, true, comp, doc)
  228. {}
  229. void setText (const String& newText) override
  230. {
  231. document.perform (new ComboItemsChangeAction (component, *document.getComponentLayout(), newText),
  232. "Change combo box items");
  233. }
  234. String getText() const override
  235. {
  236. return component->getProperties() ["items"];
  237. }
  238. private:
  239. class ComboItemsChangeAction : public ComponentUndoableAction <ComboBox>
  240. {
  241. public:
  242. ComboItemsChangeAction (ComboBox* const comp, ComponentLayout& l, const String& newState_)
  243. : ComponentUndoableAction <ComboBox> (comp, l),
  244. newState (newState_)
  245. {
  246. oldState = comp->getProperties() ["items"];
  247. }
  248. bool perform()
  249. {
  250. showCorrectTab();
  251. getComponent()->getProperties().set ("items", newState);
  252. ComboBoxHandler::updateItems (getComponent());
  253. changed();
  254. return true;
  255. }
  256. bool undo()
  257. {
  258. showCorrectTab();
  259. getComponent()->getProperties().set ("items", oldState);
  260. ComboBoxHandler::updateItems (getComponent());
  261. changed();
  262. return true;
  263. }
  264. String newState, oldState;
  265. };
  266. };
  267. //==============================================================================
  268. class ComboTextWhenNoneSelectedProperty : public ComponentTextProperty <ComboBox>
  269. {
  270. public:
  271. ComboTextWhenNoneSelectedProperty (ComboBox* comp, JucerDocument& doc)
  272. : ComponentTextProperty <ComboBox> ("text when none selected", 200, false, comp, doc)
  273. {}
  274. void setText (const String& newText) override
  275. {
  276. document.perform (new ComboNonSelTextChangeAction (component, *document.getComponentLayout(), newText),
  277. "Change combo box text when nothing selected");
  278. }
  279. String getText() const override
  280. {
  281. return component->getTextWhenNothingSelected();
  282. }
  283. private:
  284. class ComboNonSelTextChangeAction : public ComponentUndoableAction <ComboBox>
  285. {
  286. public:
  287. ComboNonSelTextChangeAction (ComboBox* const comp, ComponentLayout& l, const String& newState_)
  288. : ComponentUndoableAction <ComboBox> (comp, l),
  289. newState (newState_)
  290. {
  291. oldState = comp->getTextWhenNothingSelected();
  292. }
  293. bool perform()
  294. {
  295. showCorrectTab();
  296. getComponent()->setTextWhenNothingSelected (newState);
  297. changed();
  298. return true;
  299. }
  300. bool undo()
  301. {
  302. showCorrectTab();
  303. getComponent()->setTextWhenNothingSelected (oldState);
  304. changed();
  305. return true;
  306. }
  307. String newState, oldState;
  308. };
  309. };
  310. //==============================================================================
  311. class ComboTextWhenNoItemsProperty : public ComponentTextProperty <ComboBox>
  312. {
  313. public:
  314. ComboTextWhenNoItemsProperty (ComboBox* comp, JucerDocument& doc)
  315. : ComponentTextProperty <ComboBox> ("text when no items", 200, false, comp, doc)
  316. {}
  317. void setText (const String& newText) override
  318. {
  319. document.perform (new ComboNoItemTextChangeAction (component, *document.getComponentLayout(), newText),
  320. "Change combo box 'no items' text");
  321. }
  322. String getText() const override
  323. {
  324. return component->getTextWhenNoChoicesAvailable();
  325. }
  326. private:
  327. class ComboNoItemTextChangeAction : public ComponentUndoableAction <ComboBox>
  328. {
  329. public:
  330. ComboNoItemTextChangeAction (ComboBox* const comp, ComponentLayout& l, const String& newState_)
  331. : ComponentUndoableAction <ComboBox> (comp, l),
  332. newState (newState_)
  333. {
  334. oldState = comp->getTextWhenNoChoicesAvailable();
  335. }
  336. bool perform()
  337. {
  338. showCorrectTab();
  339. getComponent()->setTextWhenNoChoicesAvailable (newState);
  340. changed();
  341. return true;
  342. }
  343. bool undo()
  344. {
  345. showCorrectTab();
  346. getComponent()->setTextWhenNoChoicesAvailable (oldState);
  347. changed();
  348. return true;
  349. }
  350. String newState, oldState;
  351. };
  352. };
  353. };